Commit a2e3293930
Changed files (8)
src/all_types.hpp
@@ -738,8 +738,6 @@ struct AstNodeSymbolExpr {
// populated by semantic analyzer
Expr resolved_expr;
- // set this to instead of analyzing the node, pretend it's a type entry and it's this one.
- TypeTableEntry *override_type_entry;
TypeEnumField *enum_field;
uint32_t err_value;
};
@@ -1439,7 +1437,6 @@ enum IrInstructionId {
IrInstructionIdElemPtr,
IrInstructionIdVarPtr,
IrInstructionIdCall,
- IrInstructionIdBuiltinCall,
IrInstructionIdConst,
IrInstructionIdReturn,
IrInstructionIdCast,
@@ -1449,6 +1446,7 @@ enum IrInstructionId {
IrInstructionIdTypeOf,
IrInstructionIdToPtrType,
IrInstructionIdPtrTypeChild,
+ IrInstructionIdSetFnTest,
};
struct IrInstruction {
@@ -1630,13 +1628,6 @@ struct IrInstructionCall {
IrInstruction **args;
};
-struct IrInstructionBuiltinCall {
- IrInstruction base;
-
- BuiltinFnEntry *fn;
- IrInstruction **args;
-};
-
struct IrInstructionConst {
IrInstruction base;
};
@@ -1698,6 +1689,13 @@ struct IrInstructionPtrTypeChild {
IrInstruction *value;
};
+struct IrInstructionSetFnTest {
+ IrInstruction base;
+
+ IrInstruction *fn_value;
+ IrInstruction *is_test;
+};
+
enum LValPurpose {
LValPurposeNone,
LValPurposeAssign,
src/analyze.cpp
@@ -17,41 +17,9 @@
#include "parser.hpp"
#include "zig_llvm.hpp"
-static TypeTableEntry *analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context,
- TypeTableEntry *expected_type, AstNode *node);
-static TypeTableEntry *analyze_expression_pointer_only(CodeGen *g, ImportTableEntry *import,
- BlockContext *context, TypeTableEntry *expected_type, AstNode *node, bool pointer_only);
-static VariableTableEntry *analyze_variable_declaration(CodeGen *g, ImportTableEntry *import,
- BlockContext *context, TypeTableEntry *expected_type, AstNode *node);
+static void resolve_enum_type(CodeGen *g, ImportTableEntry *import, TypeTableEntry *enum_type);
static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableEntry *struct_type);
-static TypeTableEntry *unwrapped_node_type(AstNode *node);
-static TypeTableEntry *analyze_error_literal_expr(CodeGen *g, ImportTableEntry *import,
- BlockContext *context, AstNode *node, Buf *err_name);
-static TypeTableEntry *analyze_block_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
- TypeTableEntry *expected_type, 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,
- TypeTableEntry *expected_type, uint64_t x, bool depends_on_compile_var);
-static TypeTableEntry *resolve_expr_const_val_as_bool(CodeGen *g, AstNode *node, bool value,
- bool depends_on_compile_var);
-static TypeTableEntry *analyze_decl_ref(CodeGen *g, AstNode *source_node, AstNode *decl_node,
- bool pointer_only, BlockContext *block_context, bool depends_on_compile_var);
-static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTableEntry *import,
- BlockContext *context, AstNode *source_node,
- AstNodeVariableDeclaration *variable_declaration,
- bool expr_is_maybe, AstNode *decl_node, bool var_is_ptr);
static void scan_decls(CodeGen *g, ImportTableEntry *import, BlockContext *context, AstNode *node);
-static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry);
-static void resolve_use_decl(CodeGen *g, AstNode *node);
-static void preview_use_decl(CodeGen *g, AstNode *node);
-static VariableTableEntry *add_local_var(CodeGen *g, AstNode *source_node, ImportTableEntry *import,
- BlockContext *context, Buf *name, TypeTableEntry *type_entry, bool is_const,
- AstNode *val_node);
AstNode *first_executing_node(AstNode *node) {
switch (node->type) {
@@ -868,39 +836,52 @@ TypeTableEntry *get_underlying_type(TypeTableEntry *type_entry) {
}
}
-// If the node does not have a constant expression value with a metatype, generates an error
-// and returns invalid type. Otherwise, returns the type of the constant expression value.
-// Must be called after analyze_expression on the same node.
-static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node) {
- if (node->type == NodeTypeSymbol && node->data.symbol_expr.override_type_entry) {
- return node->data.symbol_expr.override_type_entry;
+static IrInstruction *analyze_const_value(CodeGen *g, BlockContext *scope, AstNode *node,
+ TypeTableEntry *expected_type)
+{
+ IrExecutable ir_executable = {0};
+ IrExecutable analyzed_executable = {0};
+ IrInstruction *pass1 = ir_gen(g, node, scope, &ir_executable);
+
+ if (pass1->type_entry->id == TypeTableEntryIdInvalid)
+ return g->invalid_instruction;
+
+ if (g->verbose) {
+ fprintf(stderr, "{\n");
+ ir_print(stderr, &ir_executable, 4);
+ fprintf(stderr, "}\n");
}
- Expr *expr = get_resolved_expr(node);
- assert(expr->type_entry);
- if (expr->type_entry->id == TypeTableEntryIdInvalid) {
- return g->builtin_types.entry_invalid;
- } else if (expr->type_entry->id == TypeTableEntryIdMetaType) {
- // OK
- } else {
- add_node_error(g, node, buf_sprintf("expected type, found expression"));
- return g->builtin_types.entry_invalid;
+ TypeTableEntry *result_type = ir_analyze(g, &ir_executable, &analyzed_executable, expected_type, node);
+ if (result_type->id == TypeTableEntryIdInvalid)
+ return g->invalid_instruction;
+
+ if (g->verbose) {
+ fprintf(stderr, "{ // (analyzed)\n");
+ ir_print(stderr, &analyzed_executable, 4);
+ fprintf(stderr, "}\n");
}
- ConstExprValue *const_val = &expr->const_val;
- if (!const_val->ok) {
+ IrInstruction *result = ir_exec_const_result(&analyzed_executable);
+ if (!result) {
add_node_error(g, node, buf_sprintf("unable to evaluate constant expression"));
- return g->builtin_types.entry_invalid;
+ return g->invalid_instruction;
}
- return const_val->data.x_type;
+ return result;
}
static TypeTableEntry *analyze_type_expr_pointer_only(CodeGen *g, ImportTableEntry *import,
BlockContext *context, AstNode *node, bool pointer_only)
{
- AstNode **node_ptr = node->parent_field;
- analyze_expression_pointer_only(g, import, context, nullptr, *node_ptr, pointer_only);
- return resolve_type(g, *node_ptr);
+ if (pointer_only)
+ zig_panic("TODO");
+
+ IrInstruction *result = analyze_const_value(g, context, node, g->builtin_types.entry_type);
+ if (result->type_entry->id == TypeTableEntryIdInvalid)
+ return g->builtin_types.entry_invalid;
+
+ assert(result->static_value.ok);
+ return result->static_value.data.x_type;
}
// Calls analyze_expression on node, and then resolve_type.
@@ -1607,6 +1588,34 @@ static void preview_fn_proto_instance(CodeGen *g, ImportTableEntry *import, AstN
}
}
+static void add_top_level_decl(CodeGen *g, ImportTableEntry *import, BlockContext *block_context,
+ AstNode *node, Buf *name)
+{
+ assert(import);
+
+ TopLevelDecl *tld = get_as_top_level_decl(node);
+ tld->import = import;
+ tld->name = name;
+
+ 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;
+
+ auto entry = block_context->decl_table.maybe_get(name);
+ if (entry) {
+ AstNode *other_decl_node = entry->value;
+ ErrorMsg *msg = add_node_error(g, node, buf_sprintf("redefinition of '%s'", buf_ptr(name)));
+ add_error_note(g, msg, other_decl_node, buf_sprintf("previous definition is here"));
+ } else {
+ block_context->decl_table.put(name, node);
+ }
+}
+
static void scan_struct_decl(CodeGen *g, ImportTableEntry *import, BlockContext *context, AstNode *node) {
assert(node->type == NodeTypeContainerDecl);
@@ -1629,30 +1638,27 @@ static void scan_struct_decl(CodeGen *g, ImportTableEntry *import, BlockContext
}
}
-static void resolve_struct_instance(CodeGen *g, ImportTableEntry *import, AstNode *node) {
- TypeTableEntry *type_entry = node->data.struct_decl.type_entry;
- assert(type_entry);
+static void count_inline_and_var_args(AstNode *proto_node) {
+ assert(proto_node->type == NodeTypeFnProto);
- // struct/enum member fns will get resolved independently
+ size_t *inline_arg_count = &proto_node->data.fn_proto.inline_arg_count;
+ size_t *inline_or_var_type_arg_count = &proto_node->data.fn_proto.inline_or_var_type_arg_count;
- switch (node->data.struct_decl.kind) {
- case ContainerKindStruct:
- resolve_struct_type(g, import, type_entry);
- break;
- case ContainerKindEnum:
- resolve_enum_type(g, import, type_entry);
- break;
- case ContainerKindUnion:
- resolve_union_type(g, import, type_entry);
- break;
- }
-}
+ *inline_arg_count = 0;
+ *inline_or_var_type_arg_count = 0;
-static void resolve_struct_decl(CodeGen *g, ImportTableEntry *import, AstNode *node) {
- if (node->data.struct_decl.generic_params.length > 0) {
- return preview_generic_fn_proto(g, import, node);
- } else {
- return resolve_struct_instance(g, import, node);
+ // TODO run these nodes through the type analysis system rather than looking for
+ // specialized ast nodes. this would get fooled by `{var}` instead of `var` which
+ // is supposed to be equivalent
+ for (size_t 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);
+ if (param_node->data.param_decl.is_inline) {
+ *inline_arg_count += 1;
+ *inline_or_var_type_arg_count += 1;
+ } else if (param_node->data.param_decl.type->type == NodeTypeVarLiteral) {
+ *inline_or_var_type_arg_count += 1;
+ }
}
}
@@ -1680,6 +1686,137 @@ static void preview_error_value_decl(CodeGen *g, AstNode *node) {
node->data.error_value_decl.top_level_decl.resolution = TldResolutionOk;
}
+static void scan_decls(CodeGen *g, ImportTableEntry *import, BlockContext *context, AstNode *node) {
+ switch (node->type) {
+ case NodeTypeRoot:
+ for (size_t i = 0; i < import->root->data.root.top_level_decls.length; i += 1) {
+ AstNode *child = import->root->data.root.top_level_decls.at(i);
+ scan_decls(g, import, context, child);
+ }
+ break;
+ case NodeTypeContainerDecl:
+ {
+ Buf *name = node->data.struct_decl.name;
+ add_top_level_decl(g, import, context, node, name);
+ if (node->data.struct_decl.generic_params.length == 0) {
+ scan_struct_decl(g, import, context, node);
+ }
+ }
+ break;
+ case NodeTypeFnDef:
+ node->data.fn_def.fn_proto->data.fn_proto.fn_def_node = node;
+ scan_decls(g, import, context, node->data.fn_def.fn_proto);
+ break;
+ case NodeTypeVariableDeclaration:
+ {
+ Buf *name = node->data.variable_declaration.symbol;
+ add_top_level_decl(g, import, context, node, name);
+ break;
+ }
+ case NodeTypeTypeDecl:
+ {
+ Buf *name = node->data.type_decl.symbol;
+ add_top_level_decl(g, import, context, node, name);
+ break;
+ }
+ case NodeTypeFnProto:
+ {
+ // if the name is missing, we immediately announce an error
+ Buf *fn_name = node->data.fn_proto.name;
+ if (buf_len(fn_name) == 0) {
+ node->data.fn_proto.skip = true;
+ add_node_error(g, node, buf_sprintf("missing function name"));
+ break;
+ }
+ count_inline_and_var_args(node);
+
+ add_top_level_decl(g, import, context, node, fn_name);
+ break;
+ }
+ case NodeTypeUse:
+ {
+ TopLevelDecl *tld = get_as_top_level_decl(node);
+ tld->import = import;
+ node->block_context = context;
+ g->use_queue.append(node);
+ tld->import->use_decls.append(node);
+ break;
+ }
+ case NodeTypeErrorValueDecl:
+ // error value declarations do not depend on other top level decls
+ preview_error_value_decl(g, node);
+ break;
+ case NodeTypeParamDecl:
+ case NodeTypeFnDecl:
+ case NodeTypeReturnExpr:
+ case NodeTypeDefer:
+ case NodeTypeBlock:
+ case NodeTypeBinOpExpr:
+ case NodeTypeUnwrapErrorExpr:
+ case NodeTypeFnCallExpr:
+ case NodeTypeArrayAccessExpr:
+ case NodeTypeSliceExpr:
+ case NodeTypeNumberLiteral:
+ case NodeTypeStringLiteral:
+ case NodeTypeCharLiteral:
+ case NodeTypeBoolLiteral:
+ case NodeTypeNullLiteral:
+ case NodeTypeUndefinedLiteral:
+ case NodeTypeZeroesLiteral:
+ case NodeTypeThisLiteral:
+ case NodeTypeSymbol:
+ case NodeTypePrefixOpExpr:
+ case NodeTypeIfBoolExpr:
+ case NodeTypeIfVarExpr:
+ case NodeTypeWhileExpr:
+ case NodeTypeForExpr:
+ case NodeTypeSwitchExpr:
+ case NodeTypeSwitchProng:
+ case NodeTypeSwitchRange:
+ case NodeTypeLabel:
+ case NodeTypeGoto:
+ case NodeTypeBreak:
+ case NodeTypeContinue:
+ case NodeTypeAsmExpr:
+ case NodeTypeFieldAccessExpr:
+ case NodeTypeStructField:
+ case NodeTypeContainerInitExpr:
+ case NodeTypeStructValueField:
+ case NodeTypeArrayType:
+ case NodeTypeErrorType:
+ case NodeTypeTypeLiteral:
+ case NodeTypeVarLiteral:
+ zig_unreachable();
+ }
+}
+
+static void resolve_struct_instance(CodeGen *g, ImportTableEntry *import, AstNode *node) {
+ TypeTableEntry *type_entry = node->data.struct_decl.type_entry;
+ assert(type_entry);
+
+ // struct/enum member fns will get resolved independently
+
+ switch (node->data.struct_decl.kind) {
+ case ContainerKindStruct:
+ resolve_struct_type(g, import, type_entry);
+ break;
+ case ContainerKindEnum:
+ resolve_enum_type(g, import, type_entry);
+ break;
+ case ContainerKindUnion:
+ resolve_union_type(g, import, type_entry);
+ break;
+ }
+}
+
+static void resolve_struct_decl(CodeGen *g, ImportTableEntry *import, AstNode *node) {
+ if (node->data.struct_decl.generic_params.length > 0) {
+ return preview_generic_fn_proto(g, import, node);
+ } else {
+ return resolve_struct_instance(g, import, node);
+ }
+}
+
TypeTableEntry *validate_var_type(CodeGen *g, AstNode *source_node, TypeTableEntry *type_entry) {
TypeTableEntry *underlying_type = get_underlying_type(type_entry);
switch (underlying_type->id) {
@@ -1718,75 +1855,116 @@ TypeTableEntry *validate_var_type(CodeGen *g, AstNode *source_node, TypeTableEnt
zig_unreachable();
}
-static void resolve_var_decl(CodeGen *g, ImportTableEntry *import, AstNode *node) {
- assert(node->type == NodeTypeVariableDeclaration);
-
- AstNodeVariableDeclaration *var_decl = &node->data.variable_declaration;
- BlockContext *scope = node->block_context;
- bool is_const = var_decl->is_const;
- bool is_export = (var_decl->top_level_decl.visib_mod == VisibModExport);
- bool is_extern = var_decl->is_extern;
-
- assert(!scope->fn_entry);
-
- TypeTableEntry *explicit_type = nullptr;
- if (var_decl->type) {
- TypeTableEntry *proposed_type = analyze_type_expr(g, import, scope, var_decl->type);
- explicit_type = validate_var_type(g, var_decl->type, proposed_type);
- }
+// Set name to nullptr to make the variable anonymous (not visible to programmer).
+// TODO merge with definition of add_local_var in ir.cpp
+static VariableTableEntry *add_local_var_shadowable(CodeGen *g, AstNode *source_node, ImportTableEntry *import,
+ BlockContext *context, Buf *name, TypeTableEntry *type_entry, bool is_const, AstNode *val_node,
+ bool shadowable)
+{
+ VariableTableEntry *variable_entry = allocate<VariableTableEntry>(1);
+ variable_entry->type = type_entry;
+ variable_entry->block_context = context;
+ variable_entry->import = import;
+ variable_entry->shadowable = shadowable;
+ variable_entry->mem_slot_index = SIZE_MAX;
- TypeTableEntry *implicit_type = nullptr;
- if (explicit_type && explicit_type->id == TypeTableEntryIdInvalid) {
- implicit_type = explicit_type;
- } else if (var_decl->expr) {
- IrExecutable ir_executable = {0};
- IrExecutable analyzed_executable = {0};
- IrInstruction *result = ir_gen(g, var_decl->expr, scope, &ir_executable);
- if (result == g->invalid_instruction) {
- // ignore the poison value
- implicit_type = g->builtin_types.entry_invalid;
- } else {
- if (g->verbose) {
- fprintf(stderr, "var %s = {\n", buf_ptr(var_decl->symbol));
- ir_print(stderr, &ir_executable, 4);
- fprintf(stderr, "}\n");
- }
- implicit_type = ir_analyze(g, &ir_executable, &analyzed_executable,
- explicit_type, var_decl->type);
- if (g->verbose) {
- fprintf(stderr, "var %s = { // (analyzed)\n", buf_ptr(var_decl->symbol));
- ir_print(stderr, &analyzed_executable, 4);
- fprintf(stderr, "}\n");
- }
+ if (name) {
+ buf_init_from_buf(&variable_entry->name, name);
- if (implicit_type->id == TypeTableEntryIdUnreachable) {
- add_node_error(g, node,
- buf_sprintf("variable initialization is unreachable"));
- implicit_type = g->builtin_types.entry_invalid;
- } else if ((!is_const || is_export) &&
- (implicit_type->id == TypeTableEntryIdNumLitFloat ||
- implicit_type->id == TypeTableEntryIdNumLitInt))
- {
- add_node_error(g, node, buf_sprintf("unable to infer variable type"));
- implicit_type = g->builtin_types.entry_invalid;
- } else if (implicit_type->id == TypeTableEntryIdMetaType && !is_const) {
- add_node_error(g, node, buf_sprintf("variable of type 'type' must be constant"));
- implicit_type = g->builtin_types.entry_invalid;
- }
- if (implicit_type->id != TypeTableEntryIdInvalid) {
- Expr *expr = get_resolved_expr(var_decl->expr);
- IrInstruction *result = ir_exec_const_result(&analyzed_executable);
- if (result) {
- assert(result->static_value.ok);
- expr->const_val = result->static_value;
- expr->type_entry = result->type_entry;
+ if (type_entry->id != TypeTableEntryIdInvalid) {
+ VariableTableEntry *existing_var = find_variable(g, context, name);
+ if (existing_var && !existing_var->shadowable) {
+ ErrorMsg *msg = add_node_error(g, source_node,
+ buf_sprintf("redeclaration of variable '%s'", buf_ptr(name)));
+ add_error_note(g, msg, existing_var->decl_node, buf_sprintf("previous declaration is here"));
+ variable_entry->type = g->builtin_types.entry_invalid;
+ } else {
+ auto primitive_table_entry = g->primitive_type_table.maybe_get(name);
+ if (primitive_table_entry) {
+ TypeTableEntry *type = primitive_table_entry->value;
+ add_node_error(g, source_node,
+ buf_sprintf("variable shadows type '%s'", buf_ptr(&type->name)));
+ variable_entry->type = g->builtin_types.entry_invalid;
} else {
- add_node_error(g, first_executing_node(var_decl->expr),
- buf_sprintf("global variable initializer requires constant expression"));
- implicit_type = g->builtin_types.entry_invalid;
+ AstNode *decl_node = find_decl(context, name);
+ if (decl_node && decl_node->type != NodeTypeVariableDeclaration) {
+ ErrorMsg *msg = add_node_error(g, source_node,
+ buf_sprintf("redefinition of '%s'", buf_ptr(name)));
+ add_error_note(g, msg, decl_node, buf_sprintf("previous definition is here"));
+ variable_entry->type = g->builtin_types.entry_invalid;
+ }
}
}
}
+
+ context->var_table.put(&variable_entry->name, variable_entry);
+ } else {
+ // TODO replace _anon with @anon and make sure all tests still pass
+ buf_init_from_str(&variable_entry->name, "_anon");
+ }
+ if (context->fn_entry) {
+ context->fn_entry->variable_list.append(variable_entry);
+ }
+
+ variable_entry->src_is_const = is_const;
+ variable_entry->gen_is_const = is_const;
+ variable_entry->decl_node = source_node;
+ variable_entry->val_node = val_node;
+
+
+ return variable_entry;
+}
+
+static VariableTableEntry *add_local_var(CodeGen *g, AstNode *source_node, ImportTableEntry *import,
+ BlockContext *context, Buf *name, TypeTableEntry *type_entry, bool is_const, AstNode *val_node)
+{
+ return add_local_var_shadowable(g, source_node, import, context, name, type_entry, is_const, val_node, false);
+}
+
+static void resolve_var_decl(CodeGen *g, ImportTableEntry *import, AstNode *node) {
+ assert(node->type == NodeTypeVariableDeclaration);
+
+ AstNodeVariableDeclaration *var_decl = &node->data.variable_declaration;
+ BlockContext *scope = node->block_context;
+ bool is_const = var_decl->is_const;
+ bool is_export = (var_decl->top_level_decl.visib_mod == VisibModExport);
+ bool is_extern = var_decl->is_extern;
+
+ assert(!scope->fn_entry);
+
+ TypeTableEntry *explicit_type = nullptr;
+ if (var_decl->type) {
+ TypeTableEntry *proposed_type = analyze_type_expr(g, import, scope, var_decl->type);
+ explicit_type = validate_var_type(g, var_decl->type, proposed_type);
+ }
+
+ TypeTableEntry *implicit_type = nullptr;
+ if (explicit_type && explicit_type->id == TypeTableEntryIdInvalid) {
+ implicit_type = explicit_type;
+ } else if (var_decl->expr) {
+ IrInstruction *result = analyze_const_value(g, scope, var_decl->expr, explicit_type);
+ assert(result);
+ implicit_type = result->type_entry;
+
+ if (implicit_type->id == TypeTableEntryIdUnreachable) {
+ add_node_error(g, node, buf_sprintf("variable initialization is unreachable"));
+ implicit_type = g->builtin_types.entry_invalid;
+ } else if ((!is_const || is_export) &&
+ (implicit_type->id == TypeTableEntryIdNumLitFloat ||
+ implicit_type->id == TypeTableEntryIdNumLitInt))
+ {
+ add_node_error(g, node, buf_sprintf("unable to infer variable type"));
+ implicit_type = g->builtin_types.entry_invalid;
+ } else if (implicit_type->id == TypeTableEntryIdMetaType && !is_const) {
+ add_node_error(g, node, buf_sprintf("variable of type 'type' must be constant"));
+ implicit_type = g->builtin_types.entry_invalid;
+ }
+ if (implicit_type->id != TypeTableEntryIdInvalid) {
+ Expr *expr = get_resolved_expr(var_decl->expr);
+ assert(result->static_value.ok);
+ expr->const_val = result->static_value;
+ expr->type_entry = result->type_entry;
+ }
} else if (!is_extern) {
add_node_error(g, node, buf_sprintf("variables must be initialized"));
implicit_type = g->builtin_types.entry_invalid;
@@ -1906,30 +2084,6 @@ void resolve_top_level_decl(CodeGen *g, AstNode *node, bool pointer_only) {
tld->dep_loop_flag = false;
}
-static FnTableEntry *get_context_fn_entry(BlockContext *context) {
- assert(context->fn_entry);
- return context->fn_entry;
-}
-
-static TypeTableEntry *unwrapped_node_type(AstNode *node) {
- Expr *expr = get_resolved_expr(node);
- if (expr->type_entry->id == TypeTableEntryIdInvalid) {
- return expr->type_entry;
- }
- assert(expr->type_entry->id == TypeTableEntryIdMetaType);
- ConstExprValue *const_val = &expr->const_val;
- assert(const_val->ok);
- return const_val->data.x_type;
-}
-
-static TypeTableEntry *get_return_type(BlockContext *context) {
- FnTableEntry *fn_entry = get_context_fn_entry(context);
- AstNode *fn_proto_node = fn_entry->proto_node;
- assert(fn_proto_node->type == NodeTypeFnProto);
- AstNode *return_type_node = fn_proto_node->data.fn_proto.return_type;
- return unwrapped_node_type(return_type_node);
-}
-
static bool type_has_codegen_value(TypeTableEntry *type_entry) {
switch (type_entry->id) {
case TypeTableEntryIdInvalid:
@@ -1968,18 +2122,6 @@ static bool type_has_codegen_value(TypeTableEntry *type_entry) {
zig_unreachable();
}
-static void add_global_const_expr(CodeGen *g, AstNode *expr_node) {
- Expr *expr = get_resolved_expr(expr_node);
- if (expr->const_val.ok &&
- type_has_codegen_value(expr->type_entry) &&
- !expr->has_global_const &&
- type_has_bits(expr->type_entry))
- {
- g->global_const_list.append(expr_node);
- expr->has_global_const = true;
- }
-}
-
static bool num_lit_fits_in_other_type(CodeGen *g, AstNode *literal_node, TypeTableEntry *other_type) {
TypeTableEntry *other_type_underlying = get_underlying_type(other_type);
@@ -2105,85 +2247,6 @@ bool types_match_const_cast_only(TypeTableEntry *expected_type, TypeTableEntry *
return false;
}
-static TypeTableEntry *determine_peer_type_compatibility(CodeGen *g, AstNode *parent_source_node,
- AstNode **child_nodes, TypeTableEntry **child_types, size_t child_count)
-{
- TypeTableEntry *prev_type = child_types[0];
- AstNode *prev_node = child_nodes[0];
- if (prev_type->id == TypeTableEntryIdInvalid) {
- return prev_type;
- }
- for (size_t i = 1; i < child_count; i += 1) {
- TypeTableEntry *cur_type = child_types[i];
- AstNode *cur_node = child_nodes[i];
- if (cur_type->id == TypeTableEntryIdInvalid) {
- return cur_type;
- } else if (types_match_const_cast_only(prev_type, cur_type)) {
- continue;
- } else if (types_match_const_cast_only(cur_type, prev_type)) {
- prev_type = cur_type;
- prev_node = cur_node;
- continue;
- } else if (prev_type->id == TypeTableEntryIdUnreachable) {
- prev_type = cur_type;
- prev_node = cur_node;
- } else if (cur_type->id == TypeTableEntryIdUnreachable) {
- continue;
- } else if (prev_type->id == TypeTableEntryIdInt &&
- cur_type->id == TypeTableEntryIdInt &&
- prev_type->data.integral.is_signed == cur_type->data.integral.is_signed)
- {
- if (cur_type->data.integral.bit_count > prev_type->data.integral.bit_count) {
- prev_type = cur_type;
- prev_node = cur_node;
- }
- continue;
- } else if (prev_type->id == TypeTableEntryIdFloat &&
- cur_type->id == TypeTableEntryIdFloat)
- {
- if (cur_type->data.floating.bit_count > prev_type->data.floating.bit_count) {
- prev_type = cur_type;
- prev_node = cur_node;
- }
- } else if (prev_type->id == TypeTableEntryIdErrorUnion &&
- types_match_const_cast_only(prev_type->data.error.child_type, cur_type))
- {
- continue;
- } else if (cur_type->id == TypeTableEntryIdErrorUnion &&
- types_match_const_cast_only(cur_type->data.error.child_type, prev_type))
- {
- prev_type = cur_type;
- prev_node = cur_node;
- continue;
- } else if (prev_type->id == TypeTableEntryIdNumLitInt ||
- prev_type->id == TypeTableEntryIdNumLitFloat)
- {
- if (num_lit_fits_in_other_type(g, prev_node, cur_type)) {
- prev_type = cur_type;
- prev_node = cur_node;
- continue;
- } else {
- return g->builtin_types.entry_invalid;
- }
- } else if (cur_type->id == TypeTableEntryIdNumLitInt ||
- cur_type->id == TypeTableEntryIdNumLitFloat)
- {
- if (num_lit_fits_in_other_type(g, cur_node, prev_type)) {
- continue;
- } else {
- return g->builtin_types.entry_invalid;
- }
- } else {
- add_node_error(g, parent_source_node,
- buf_sprintf("incompatible types: '%s' and '%s'",
- buf_ptr(&prev_type->name), buf_ptr(&cur_type->name)));
-
- return g->builtin_types.entry_invalid;
- }
- }
- return prev_type;
-}
-
static bool types_match_with_implicit_cast(CodeGen *g, TypeTableEntry *expected_type,
TypeTableEntry *actual_type, AstNode *literal_node, bool *reported_err)
{
@@ -2272,104 +2335,6 @@ static bool types_match_with_implicit_cast(CodeGen *g, TypeTableEntry *expected_
return false;
}
-static AstNode *create_ast_node(CodeGen *g, ImportTableEntry *import, NodeType kind, AstNode *source_node) {
- AstNode *node = allocate<AstNode>(1);
- node->type = kind;
- node->owner = import;
- node->create_index = g->next_node_index;
- g->next_node_index += 1;
- node->line = source_node->line;
- node->column = source_node->column;
- return node;
-}
-
-static AstNode *create_ast_type_node(CodeGen *g, ImportTableEntry *import, TypeTableEntry *type_entry,
- AstNode *source_node)
-{
- AstNode *node = create_ast_node(g, import, NodeTypeSymbol, source_node);
- node->data.symbol_expr.override_type_entry = type_entry;
- return node;
-}
-
-static AstNode *create_ast_void_node(CodeGen *g, ImportTableEntry *import, AstNode *source_node) {
- AstNode *node = create_ast_node(g, import, NodeTypeContainerInitExpr, source_node);
- node->data.container_init_expr.kind = ContainerInitKindArray;
- node->data.container_init_expr.type = create_ast_type_node(g, import, g->builtin_types.entry_void,
- source_node);
- normalize_parent_ptrs(node);
- return node;
-}
-
-static TypeTableEntry *create_and_analyze_cast_node(CodeGen *g, ImportTableEntry *import,
- BlockContext *context, TypeTableEntry *cast_to_type, AstNode *node)
-{
- AstNode *new_parent_node = create_ast_node(g, import, NodeTypeFnCallExpr, node);
- *node->parent_field = new_parent_node;
- new_parent_node->parent_field = node->parent_field;
-
- new_parent_node->data.fn_call_expr.fn_ref_expr = create_ast_type_node(g, import, cast_to_type, node);
- new_parent_node->data.fn_call_expr.params.append(node);
- normalize_parent_ptrs(new_parent_node);
-
- return analyze_expression(g, import, context, cast_to_type, new_parent_node);
-}
-
-static TypeTableEntry *resolve_type_compatibility(CodeGen *g, ImportTableEntry *import,
- BlockContext *context, AstNode *node,
- TypeTableEntry *expected_type, TypeTableEntry *actual_type)
-{
- if (expected_type == nullptr)
- return actual_type; // anything will do
- if (expected_type == actual_type)
- return expected_type; // match
- if (expected_type->id == TypeTableEntryIdInvalid || actual_type->id == TypeTableEntryIdInvalid)
- return g->builtin_types.entry_invalid;
- if (actual_type->id == TypeTableEntryIdUnreachable)
- return actual_type;
-
- bool reported_err = false;
- if (types_match_with_implicit_cast(g, expected_type, actual_type, node, &reported_err)) {
- return create_and_analyze_cast_node(g, import, context, expected_type, node);
- }
-
- if (!reported_err) {
- add_node_error(g, first_executing_node(node),
- buf_sprintf("expected type '%s', got '%s'",
- buf_ptr(&expected_type->name),
- buf_ptr(&actual_type->name)));
- }
-
- return g->builtin_types.entry_invalid;
-}
-
-TypeTableEntry *resolve_peer_type_compatibility(CodeGen *g, ImportTableEntry *import,
- BlockContext *block_context, AstNode *parent_source_node,
- AstNode **child_nodes, TypeTableEntry **child_types, size_t child_count)
-{
- assert(child_count > 0);
-
- TypeTableEntry *expected_type = determine_peer_type_compatibility(g, parent_source_node,
- child_nodes, child_types, child_count);
-
- if (expected_type->id == TypeTableEntryIdInvalid) {
- return expected_type;
- }
-
- for (size_t i = 0; i < child_count; i += 1) {
- if (!child_nodes[i]) {
- continue;
- }
- AstNode **child_node = child_nodes[i]->parent_field;
- TypeTableEntry *resolved_type = resolve_type_compatibility(g, import, block_context,
- *child_node, expected_type, child_types[i]);
- Expr *expr = get_resolved_expr(*child_node);
- expr->type_entry = resolved_type;
- add_global_const_expr(g, *child_node);
- }
-
- return expected_type;
-}
-
BlockContext *new_block_context(AstNode *node, BlockContext *parent) {
BlockContext *context = allocate<BlockContext>(1);
context->node = node;
@@ -2432,67 +2397,6 @@ TypeEnumField *find_enum_type_field(TypeTableEntry *enum_type, Buf *name) {
return nullptr;
}
-static TypeTableEntry *analyze_enum_value_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
- AstNode *field_access_node, AstNode *value_node, TypeTableEntry *enum_type, Buf *field_name,
- AstNode *out_node)
-{
- assert(field_access_node->type == NodeTypeFieldAccessExpr);
-
- TypeEnumField *type_enum_field = find_enum_type_field(enum_type, field_name);
- if (type_enum_field->type_entry->id == TypeTableEntryIdInvalid) {
- return g->builtin_types.entry_invalid;
- }
-
- field_access_node->data.field_access_expr.type_enum_field = type_enum_field;
-
- if (type_enum_field) {
- if (value_node) {
- AstNode **value_node_ptr = value_node->parent_field;
- TypeTableEntry *value_type = analyze_expression(g, import, context,
- type_enum_field->type_entry, value_node);
-
- if (value_type->id == TypeTableEntryIdInvalid) {
- return g->builtin_types.entry_invalid;
- }
-
- StructValExprCodeGen *codegen = &field_access_node->data.field_access_expr.resolved_struct_val_expr;
- codegen->type_entry = enum_type;
- codegen->source_node = field_access_node;
-
- ConstExprValue *value_const_val = &get_resolved_expr(*value_node_ptr)->const_val;
- if (value_const_val->ok) {
- ConstExprValue *const_val = &get_resolved_expr(out_node)->const_val;
- const_val->ok = true;
- const_val->data.x_enum.tag = type_enum_field->value;
- const_val->data.x_enum.payload = value_const_val;
- } else {
- if (context->fn_entry) {
- context->fn_entry->struct_val_expr_alloca_list.append(codegen);
- } else {
- add_node_error(g, *value_node_ptr, buf_sprintf("unable to evaluate constant expression"));
- return g->builtin_types.entry_invalid;
- }
- }
- } else if (type_enum_field->type_entry->id != TypeTableEntryIdVoid) {
- add_node_error(g, field_access_node,
- buf_sprintf("enum value '%s.%s' requires parameter of type '%s'",
- buf_ptr(&enum_type->name),
- buf_ptr(field_name),
- buf_ptr(&type_enum_field->type_entry->name)));
- } else {
- Expr *expr = get_resolved_expr(out_node);
- expr->const_val.ok = true;
- expr->const_val.data.x_enum.tag = type_enum_field->value;
- expr->const_val.data.x_enum.payload = nullptr;
- }
- } else {
- add_node_error(g, field_access_node,
- buf_sprintf("no member named '%s' in '%s'", buf_ptr(field_name),
- buf_ptr(&enum_type->name)));
- }
- return enum_type;
-}
-
TypeStructField *find_struct_type_field(TypeTableEntry *type_entry, Buf *name) {
assert(type_entry->id == TypeTableEntryIdStruct);
assert(type_entry->data.structure.complete);
@@ -2587,2703 +2491,50 @@ void resolve_container_type(CodeGen *g, TypeTableEntry *type_entry) {
}
}
-static TypeTableEntry *analyze_container_member_access_inner(CodeGen *g,
- TypeTableEntry *bare_struct_type, Buf *field_name, AstNode *node, TypeTableEntry *struct_type)
-{
- assert(node->type == NodeTypeFieldAccessExpr);
- if (!is_slice(bare_struct_type)) {
- BlockContext *container_block_context = get_container_block_context(bare_struct_type);
- assert(container_block_context);
- auto entry = container_block_context->decl_table.maybe_get(field_name);
- AstNode *fn_decl_node = entry ? entry->value : nullptr;
- if (fn_decl_node && fn_decl_node->type == NodeTypeFnProto) {
- resolve_top_level_decl(g, fn_decl_node, false);
- TopLevelDecl *tld = get_as_top_level_decl(fn_decl_node);
- if (tld->resolution == TldResolutionInvalid) {
- return g->builtin_types.entry_invalid;
- }
-
- node->data.field_access_expr.is_member_fn = true;
- FnTableEntry *fn_entry = fn_decl_node->data.fn_proto.fn_table_entry;
- 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);
- }
- }
+bool type_is_codegen_pointer(TypeTableEntry *type) {
+ if (type->id == TypeTableEntryIdPointer) return true;
+ if (type->id == TypeTableEntryIdFn) return true;
+ if (type->id == TypeTableEntryIdMaybe) {
+ if (type->data.maybe.child_type->id == TypeTableEntryIdPointer) return true;
+ if (type->data.maybe.child_type->id == TypeTableEntryIdFn) return true;
}
- add_node_error(g, node,
- buf_sprintf("no member named '%s' in '%s'", buf_ptr(field_name), buf_ptr(&bare_struct_type->name)));
- return g->builtin_types.entry_invalid;
+ return false;
}
-static TypeTableEntry *analyze_container_member_access(CodeGen *g,
- Buf *field_name, AstNode *node, TypeTableEntry *struct_type)
-{
- TypeTableEntry *bare_type = container_ref_type(struct_type);
- if (!type_is_complete(bare_type)) {
- resolve_container_type(g, bare_type);
- }
- node->data.field_access_expr.bare_container_type = bare_type;
- if (bare_type->id == TypeTableEntryIdStruct) {
- node->data.field_access_expr.type_struct_field = find_struct_type_field(bare_type, field_name);
- if (node->data.field_access_expr.type_struct_field) {
- return node->data.field_access_expr.type_struct_field->type_entry;
- } else {
- return analyze_container_member_access_inner(g, bare_type, field_name,
- node, struct_type);
- }
- } else if (bare_type->id == TypeTableEntryIdEnum) {
- node->data.field_access_expr.type_enum_field = find_enum_type_field(bare_type, field_name);
- if (node->data.field_access_expr.type_enum_field) {
- return node->data.field_access_expr.type_enum_field->type_entry;
- } else {
- return analyze_container_member_access_inner(g, bare_type, field_name,
- node, struct_type);
- }
- } else if (bare_type->id == TypeTableEntryIdUnion) {
- zig_panic("TODO");
- } else {
- zig_unreachable();
- }
-}
+static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) {
+ ImportTableEntry *import = fn_table_entry->import_entry;
+ AstNode *node = fn_table_entry->fn_def_node;
+ assert(node->type == NodeTypeFnDef);
-static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
- TypeTableEntry *expected_type, AstNode *node)
-{
- assert(node->type == NodeTypeFieldAccessExpr);
-
- AstNode **struct_expr_node = &node->data.field_access_expr.struct_expr;
- TypeTableEntry *struct_type = analyze_expression(g, import, context, nullptr, *struct_expr_node);
- Buf *field_name = node->data.field_access_expr.field_name;
-
- if (struct_type->id == TypeTableEntryIdInvalid) {
- return struct_type;
- } else if (is_container_ref(struct_type)) {
- return analyze_container_member_access(g, field_name, node, struct_type);
- } else if (struct_type->id == TypeTableEntryIdArray) {
- if (buf_eql_str(field_name, "len")) {
- return resolve_expr_const_val_as_unsigned_num_lit(g, node, expected_type,
- struct_type->data.array.len, false);
- } else {
- add_node_error(g, node,
- buf_sprintf("no member named '%s' in '%s'", buf_ptr(field_name),
- buf_ptr(&struct_type->name)));
- return g->builtin_types.entry_invalid;
- }
- } else if (struct_type->id == TypeTableEntryIdMetaType) {
- TypeTableEntry *child_type = resolve_type(g, *struct_expr_node);
+ AstNode *fn_proto_node = node->data.fn_def.fn_proto;
+ assert(fn_proto_node->type == NodeTypeFnProto);
- if (child_type->id == TypeTableEntryIdInvalid) {
- return g->builtin_types.entry_invalid;
- } else if (child_type->id == TypeTableEntryIdEnum) {
- AstNode *container_init_node = node->data.field_access_expr.container_init_expr_node;
- AstNode *value_node;
- if (container_init_node) {
- assert(container_init_node->type == NodeTypeContainerInitExpr);
- size_t param_count = container_init_node->data.container_init_expr.entries.length;
- if (param_count > 1) {
- AstNode *first_invalid_node = container_init_node->data.container_init_expr.entries.at(1);
- add_node_error(g, first_executing_node(first_invalid_node),
- buf_sprintf("enum values accept only one parameter"));
- return child_type;
- } else {
- if (param_count == 1) {
- value_node = container_init_node->data.container_init_expr.entries.at(0);
- } else {
- value_node = nullptr;
- }
- container_init_node->data.container_init_expr.enum_type = child_type;
- }
- } else {
- value_node = nullptr;
- }
- return analyze_enum_value_expr(g, import, context, node, value_node, child_type, field_name, node);
- } else if (child_type->id == TypeTableEntryIdStruct) {
- BlockContext *container_block_context = get_container_block_context(child_type);
- auto entry = container_block_context->decl_table.maybe_get(field_name);
- AstNode *decl_node = entry ? entry->value : nullptr;
- if (decl_node) {
- bool pointer_only = false;
- return analyze_decl_ref(g, node, decl_node, pointer_only, context, false);
- } else {
- add_node_error(g, node,
- buf_sprintf("container '%s' has no member called '%s'",
- buf_ptr(&child_type->name), buf_ptr(field_name)));
- return g->builtin_types.entry_invalid;
- }
- } else if (child_type->id == TypeTableEntryIdPureError) {
- return analyze_error_literal_expr(g, import, context, node, field_name);
- } else if (child_type->id == TypeTableEntryIdInt) {
- bool depends_on_compile_var =
- get_resolved_expr(*struct_expr_node)->const_val.depends_on_compile_var;
- if (buf_eql_str(field_name, "bit_count")) {
- return resolve_expr_const_val_as_unsigned_num_lit(g, node, expected_type,
- child_type->data.integral.bit_count, depends_on_compile_var);
- } else if (buf_eql_str(field_name, "is_signed")) {
- return resolve_expr_const_val_as_bool(g, node, child_type->data.integral.is_signed,
- depends_on_compile_var);
- } else {
- add_node_error(g, node,
- buf_sprintf("type '%s' has no member called '%s'",
- buf_ptr(&child_type->name), buf_ptr(field_name)));
- return g->builtin_types.entry_invalid;
- }
- } else {
- add_node_error(g, node,
- buf_sprintf("type '%s' does not support field access", buf_ptr(&struct_type->name)));
- return g->builtin_types.entry_invalid;
- }
- } else if (struct_type->id == TypeTableEntryIdNamespace) {
- ConstExprValue *const_val = &get_resolved_expr(*struct_expr_node)->const_val;
- assert(const_val->ok);
- ImportTableEntry *namespace_import = const_val->data.x_import;
- AstNode *decl_node = find_decl(namespace_import->block_context, field_name);
- if (!decl_node) {
- // we must now resolve all the use decls
- for (size_t i = 0; i < namespace_import->use_decls.length; i += 1) {
- AstNode *use_decl_node = namespace_import->use_decls.at(i);
- if (!get_resolved_expr(use_decl_node->data.use.expr)->type_entry) {
- preview_use_decl(g, use_decl_node);
- }
- resolve_use_decl(g, use_decl_node);
- }
- decl_node = find_decl(namespace_import->block_context, field_name);
- }
- if (decl_node) {
- TopLevelDecl *tld = get_as_top_level_decl(decl_node);
- if (tld->visib_mod == VisibModPrivate && decl_node->owner != import) {
- ErrorMsg *msg = add_node_error(g, node,
- buf_sprintf("'%s' is private", buf_ptr(field_name)));
- add_error_note(g, msg, decl_node, buf_sprintf("declared here"));
- }
- bool pointer_only = false;
- return analyze_decl_ref(g, node, decl_node, pointer_only, context,
- const_val->depends_on_compile_var);
- } else {
- const char *import_name = namespace_import->path ? buf_ptr(namespace_import->path) : "(C import)";
- add_node_error(g, node,
- buf_sprintf("no member named '%s' in '%s'", buf_ptr(field_name), import_name));
- return g->builtin_types.entry_invalid;
- }
- } else {
- add_node_error(g, node,
- buf_sprintf("type '%s' does not support field access", buf_ptr(&struct_type->name)));
- return g->builtin_types.entry_invalid;
+ if (fn_proto_node->data.fn_proto.skip) {
+ // we detected an error with this function definition which prevents us
+ // from further analyzing it.
+ fn_table_entry->anal_state = FnAnalStateSkipped;
+ return;
}
-}
+ fn_table_entry->anal_state = FnAnalStateProbing;
-static TypeTableEntry *analyze_slice_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
- AstNode *node)
-{
- assert(node->type == NodeTypeSliceExpr);
-
- TypeTableEntry *array_type = analyze_expression(g, import, context, nullptr,
- node->data.slice_expr.array_ref_expr);
-
- TypeTableEntry *return_type;
-
- if (array_type->id == TypeTableEntryIdInvalid) {
- return_type = g->builtin_types.entry_invalid;
- } else if (array_type->id == TypeTableEntryIdArray) {
- return_type = get_slice_type(g, array_type->data.array.child_type,
- node->data.slice_expr.is_const);
- } else if (array_type->id == TypeTableEntryIdPointer) {
- return_type = get_slice_type(g, array_type->data.pointer.child_type,
- node->data.slice_expr.is_const);
- } else if (array_type->id == TypeTableEntryIdStruct &&
- array_type->data.structure.is_slice)
- {
- return_type = get_slice_type(g,
- array_type->data.structure.fields[0].type_entry->data.pointer.child_type,
- node->data.slice_expr.is_const);
- } else {
- add_node_error(g, node,
- buf_sprintf("slice of non-array type '%s'", buf_ptr(&array_type->name)));
- return_type = g->builtin_types.entry_invalid;
- }
+ BlockContext *context = node->data.fn_def.block_context;
- if (return_type->id != TypeTableEntryIdInvalid) {
- node->data.slice_expr.resolved_struct_val_expr.type_entry = return_type;
- node->data.slice_expr.resolved_struct_val_expr.source_node = node;
- context->fn_entry->struct_val_expr_alloca_list.append(&node->data.slice_expr.resolved_struct_val_expr);
- }
+ TypeTableEntry *fn_type = fn_table_entry->type_entry;
+ FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;
+ AstNodeFnProto *fn_proto = &fn_proto_node->data.fn_proto;
+ for (size_t i = 0; i < fn_proto->params.length; i += 1) {
+ AstNode *param_decl_node = fn_proto->params.at(i);
+ assert(param_decl_node->type == NodeTypeParamDecl);
- analyze_expression(g, import, context, g->builtin_types.entry_usize, node->data.slice_expr.start);
+ // define local variables for parameters
+ AstNodeParamDecl *param_decl = ¶m_decl_node->data.param_decl;
+ TypeTableEntry *type = fn_type_id->param_info[i].type;
- if (node->data.slice_expr.end) {
- analyze_expression(g, import, context, g->builtin_types.entry_usize, node->data.slice_expr.end);
- }
-
- return return_type;
-}
-
-static TypeTableEntry *analyze_array_access_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
- AstNode *node, LValPurpose purpose)
-{
- TypeTableEntry *array_type = analyze_expression(g, import, context, nullptr,
- node->data.array_access_expr.array_ref_expr);
-
- TypeTableEntry *return_type;
-
- if (array_type->id == TypeTableEntryIdInvalid) {
- return_type = g->builtin_types.entry_invalid;
- } else if (array_type->id == TypeTableEntryIdArray) {
- if (array_type->data.array.len == 0) {
- add_node_error(g, node, buf_sprintf("out of bounds array access"));
- }
- return_type = array_type->data.array.child_type;
- } else if (array_type->id == TypeTableEntryIdPointer) {
- if (array_type->data.pointer.is_const && purpose == LValPurposeAssign) {
- add_node_error(g, node, buf_sprintf("cannot assign to constant"));
- return g->builtin_types.entry_invalid;
- }
- return_type = array_type->data.pointer.child_type;
- } else if (array_type->id == TypeTableEntryIdStruct &&
- array_type->data.structure.is_slice)
- {
- TypeTableEntry *pointer_type = array_type->data.structure.fields[0].type_entry;
- if (pointer_type->data.pointer.is_const && purpose == LValPurposeAssign) {
- add_node_error(g, node, buf_sprintf("cannot assign to constant"));
- return g->builtin_types.entry_invalid;
- }
- return_type = pointer_type->data.pointer.child_type;
- } else {
- add_node_error(g, node,
- buf_sprintf("array access of non-array type '%s'", buf_ptr(&array_type->name)));
- return_type = g->builtin_types.entry_invalid;
- }
-
- analyze_expression(g, import, context, g->builtin_types.entry_usize, node->data.array_access_expr.subscript);
-
- return return_type;
-}
-
-static TypeTableEntry *resolve_expr_const_val_as_type(CodeGen *g, AstNode *node, TypeTableEntry *type,
- bool depends_on_compile_var)
-{
- Expr *expr = get_resolved_expr(node);
- expr->const_val.ok = true;
- expr->const_val.data.x_type = type;
- expr->const_val.depends_on_compile_var = depends_on_compile_var;
- return g->builtin_types.entry_type;
-}
-
-static TypeTableEntry *resolve_expr_const_val_as_other_expr(CodeGen *g, AstNode *node, AstNode *other,
- bool depends_on_compile_var)
-{
- Expr *expr = get_resolved_expr(node);
- Expr *other_expr = get_resolved_expr(other);
- expr->const_val = other_expr->const_val;
- expr->const_val.depends_on_compile_var = expr->const_val.depends_on_compile_var ||
- depends_on_compile_var;
- return other_expr->type_entry;
-}
-
-static TypeTableEntry *resolve_expr_const_val_as_fn(CodeGen *g, AstNode *node, FnTableEntry *fn,
- bool depends_on_compile_var)
-{
- Expr *expr = get_resolved_expr(node);
- expr->const_val.ok = true;
- expr->const_val.data.x_fn = fn;
- expr->const_val.depends_on_compile_var = depends_on_compile_var;
- return fn->type_entry;
-}
-
-static TypeTableEntry *resolve_expr_const_val_as_generic_fn(CodeGen *g, AstNode *node,
- TypeTableEntry *type_entry, bool depends_on_compile_var)
-{
- Expr *expr = get_resolved_expr(node);
- expr->const_val.ok = true;
- expr->const_val.data.x_type = type_entry;
- expr->const_val.depends_on_compile_var = depends_on_compile_var;
- return type_entry;
-}
-
-
-static TypeTableEntry *resolve_expr_const_val_as_err(CodeGen *g, AstNode *node, ErrorTableEntry *err) {
- Expr *expr = get_resolved_expr(node);
- expr->const_val.ok = true;
- expr->const_val.data.x_err.err = err;
- return g->builtin_types.entry_pure_error;
-}
-
-static TypeTableEntry *resolve_expr_const_val_as_bool(CodeGen *g, AstNode *node, bool value,
- bool depends_on_compile_var)
-{
- Expr *expr = get_resolved_expr(node);
- expr->const_val.ok = true;
- expr->const_val.depends_on_compile_var = depends_on_compile_var;
- expr->const_val.data.x_bool = value;
- return g->builtin_types.entry_bool;
-}
-
-static TypeTableEntry *resolve_expr_const_val_as_c_string_lit(CodeGen *g, AstNode *node, Buf *str) {
- Expr *expr = get_resolved_expr(node);
- expr->const_val.ok = true;
-
- size_t len_with_null = buf_len(str) + 1;
- expr->const_val.data.x_ptr.ptr = allocate<ConstExprValue*>(len_with_null);
- expr->const_val.data.x_ptr.len = len_with_null;
- expr->const_val.data.x_ptr.is_c_str = true;
-
- ConstExprValue *all_chars = allocate<ConstExprValue>(len_with_null);
- for (size_t i = 0; i < buf_len(str); i += 1) {
- ConstExprValue *this_char = &all_chars[i];
- this_char->ok = true;
- bignum_init_unsigned(&this_char->data.x_bignum, buf_ptr(str)[i]);
- expr->const_val.data.x_ptr.ptr[i] = this_char;
- }
-
- ConstExprValue *null_char = &all_chars[len_with_null - 1];
- null_char->ok = true;
- bignum_init_unsigned(&null_char->data.x_bignum, 0);
- expr->const_val.data.x_ptr.ptr[len_with_null - 1] = null_char;
-
- return get_pointer_to_type(g, g->builtin_types.entry_u8, true);
-}
-
-static TypeTableEntry *resolve_expr_const_val_as_string_lit(CodeGen *g, AstNode *node, Buf *str) {
- Expr *expr = get_resolved_expr(node);
- expr->const_val.ok = true;
- expr->const_val.data.x_array.fields = allocate<ConstExprValue*>(buf_len(str));
-
- ConstExprValue *all_chars = allocate<ConstExprValue>(buf_len(str));
- for (size_t i = 0; i < buf_len(str); i += 1) {
- ConstExprValue *this_char = &all_chars[i];
- this_char->ok = true;
- bignum_init_unsigned(&this_char->data.x_bignum, buf_ptr(str)[i]);
- expr->const_val.data.x_array.fields[i] = this_char;
- }
- return get_array_type(g, g->builtin_types.entry_u8, buf_len(str));
-}
-
-static TypeTableEntry *resolve_expr_const_val_as_bignum(CodeGen *g, AstNode *node,
- TypeTableEntry *expected_type, BigNum *bignum, bool depends_on_compile_var)
-{
- Expr *expr = get_resolved_expr(node);
- expr->const_val.ok = true;
- expr->const_val.depends_on_compile_var = depends_on_compile_var;
-
- bignum_init_bignum(&expr->const_val.data.x_bignum, bignum);
- if (bignum->kind == BigNumKindInt) {
- return g->builtin_types.entry_num_lit_int;
- } else if (bignum->kind == BigNumKindFloat) {
- return g->builtin_types.entry_num_lit_float;
- } else {
- zig_unreachable();
- }
-}
-
-static TypeTableEntry *resolve_expr_const_val_as_unsigned_num_lit(CodeGen *g, AstNode *node,
- TypeTableEntry *expected_type, uint64_t x, bool depends_on_compile_var)
-{
- Expr *expr = get_resolved_expr(node);
- expr->const_val.ok = true;
- expr->const_val.depends_on_compile_var = depends_on_compile_var;
-
- bignum_init_unsigned(&expr->const_val.data.x_bignum, x);
-
- return g->builtin_types.entry_num_lit_int;
-}
-
-static TypeTableEntry *analyze_error_literal_expr(CodeGen *g, ImportTableEntry *import,
- BlockContext *context, AstNode *node, Buf *err_name)
-{
- auto err_table_entry = g->error_table.maybe_get(err_name);
-
- if (err_table_entry) {
- return resolve_expr_const_val_as_err(g, node, err_table_entry->value);
- }
-
- add_node_error(g, node,
- buf_sprintf("use of undeclared error value '%s'", buf_ptr(err_name)));
-
- return g->builtin_types.entry_invalid;
-}
-
-static bool var_is_pure(VariableTableEntry *var, BlockContext *context) {
- if (var->block_context->fn_entry == context->fn_entry) {
- // variable was declared in the current function, so it's OK.
- return true;
- }
- return var->src_is_const && var->type->deep_const;
-}
-
-static TypeTableEntry *analyze_var_ref(CodeGen *g, AstNode *source_node, VariableTableEntry *var,
- BlockContext *context, bool depends_on_compile_var)
-{
- get_resolved_expr(source_node)->variable = var;
- if (!var_is_pure(var, context)) {
- mark_impure_fn(g, context, source_node);
- }
- if (var->src_is_const && var->val_node) {
- ConstExprValue *other_const_val = &get_resolved_expr(var->val_node)->const_val;
- if (other_const_val->ok) {
- return resolve_expr_const_val_as_other_expr(g, source_node, var->val_node,
- depends_on_compile_var || var->force_depends_on_compile_var);
- }
- }
- return var->type;
-}
-
-static TypeTableEntry *analyze_decl_ref(CodeGen *g, AstNode *source_node, AstNode *decl_node,
- bool pointer_only, BlockContext *block_context, bool depends_on_compile_var)
-{
- resolve_top_level_decl(g, decl_node, pointer_only);
- TopLevelDecl *tld = get_as_top_level_decl(decl_node);
- if (tld->resolution == TldResolutionInvalid) {
- return g->builtin_types.entry_invalid;
- }
-
- if (decl_node->type == NodeTypeVariableDeclaration) {
- 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) {
- 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 {
- return resolve_expr_const_val_as_fn(g, source_node, fn_entry, depends_on_compile_var);
- }
- } else if (decl_node->type == NodeTypeContainerDecl) {
- if (decl_node->data.struct_decl.generic_params.length > 0) {
- TypeTableEntry *type_entry = decl_node->data.struct_decl.generic_fn_type;
- assert(type_entry);
- return resolve_expr_const_val_as_generic_fn(g, source_node, type_entry, depends_on_compile_var);
- } else {
- return resolve_expr_const_val_as_type(g, source_node, decl_node->data.struct_decl.type_entry,
- depends_on_compile_var);
- }
- } else if (decl_node->type == NodeTypeTypeDecl) {
- return resolve_expr_const_val_as_type(g, source_node, decl_node->data.type_decl.child_type_entry,
- depends_on_compile_var);
- } else {
- zig_unreachable();
- }
-}
-
-static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
- TypeTableEntry *expected_type, AstNode *node, bool pointer_only)
-{
- Buf *variable_name = node->data.symbol_expr.symbol;
-
- auto primitive_table_entry = g->primitive_type_table.maybe_get(variable_name);
- if (primitive_table_entry) {
- return resolve_expr_const_val_as_type(g, node, primitive_table_entry->value, false);
- }
-
- VariableTableEntry *var = find_variable(g, context, variable_name);
- if (var) {
- TypeTableEntry *var_type = analyze_var_ref(g, node, var, context, false);
- return var_type;
- }
-
- AstNode *decl_node = find_decl(context, variable_name);
- if (decl_node) {
- return analyze_decl_ref(g, node, decl_node, pointer_only, context, false);
- }
-
- if (import->any_imports_failed) {
- // skip the error message since we had a failing import in this file
- // if an import breaks we don't need 9999 undeclared identifier errors
- return g->builtin_types.entry_invalid;
- }
-
- mark_impure_fn(g, context, node);
- add_node_error(g, node, buf_sprintf("use of undeclared identifier '%s'", buf_ptr(variable_name)));
- return g->builtin_types.entry_invalid;
-}
-
-static bool is_op_allowed(TypeTableEntry *type, BinOpType op) {
- switch (op) {
- case BinOpTypeAssign:
- return true;
- case BinOpTypeAssignTimes:
- case BinOpTypeAssignTimesWrap:
- case BinOpTypeAssignDiv:
- case BinOpTypeAssignMod:
- return type->id == TypeTableEntryIdInt || type->id == TypeTableEntryIdFloat;
- case BinOpTypeAssignPlus:
- case BinOpTypeAssignPlusWrap:
- case BinOpTypeAssignMinus:
- case BinOpTypeAssignMinusWrap:
- return type->id == TypeTableEntryIdInt ||
- type->id == TypeTableEntryIdFloat ||
- type->id == TypeTableEntryIdPointer;
- case BinOpTypeAssignBitShiftLeft:
- case BinOpTypeAssignBitShiftLeftWrap:
- case BinOpTypeAssignBitShiftRight:
- case BinOpTypeAssignBitAnd:
- case BinOpTypeAssignBitXor:
- case BinOpTypeAssignBitOr:
- return type->id == TypeTableEntryIdInt;
- case BinOpTypeAssignBoolAnd:
- case BinOpTypeAssignBoolOr:
- return type->id == TypeTableEntryIdBool;
-
- case BinOpTypeInvalid:
- case BinOpTypeBoolOr:
- case BinOpTypeBoolAnd:
- case BinOpTypeCmpEq:
- case BinOpTypeCmpNotEq:
- case BinOpTypeCmpLessThan:
- case BinOpTypeCmpGreaterThan:
- case BinOpTypeCmpLessOrEq:
- case BinOpTypeCmpGreaterOrEq:
- case BinOpTypeBinOr:
- case BinOpTypeBinXor:
- case BinOpTypeBinAnd:
- case BinOpTypeBitShiftLeft:
- case BinOpTypeBitShiftLeftWrap:
- case BinOpTypeBitShiftRight:
- case BinOpTypeAdd:
- case BinOpTypeAddWrap:
- case BinOpTypeSub:
- case BinOpTypeSubWrap:
- case BinOpTypeMult:
- case BinOpTypeMultWrap:
- case BinOpTypeDiv:
- case BinOpTypeMod:
- case BinOpTypeUnwrapMaybe:
- case BinOpTypeArrayCat:
- case BinOpTypeArrayMult:
- zig_unreachable();
- }
- zig_unreachable();
-}
-
-static TypeTableEntry *analyze_lvalue(CodeGen *g, ImportTableEntry *import, BlockContext *block_context,
- AstNode *lhs_node, LValPurpose purpose, bool is_ptr_const)
-{
- TypeTableEntry *expected_rhs_type = nullptr;
- lhs_node->block_context = block_context;
- if (lhs_node->type == NodeTypeSymbol) {
- bool pointer_only = purpose == LValPurposeAddressOf;
- expected_rhs_type = analyze_symbol_expr(g, import, block_context, nullptr, lhs_node, pointer_only);
- if (expected_rhs_type->id == TypeTableEntryIdInvalid) {
- return g->builtin_types.entry_invalid;
- }
- if (purpose != LValPurposeAddressOf) {
- Buf *name = lhs_node->data.symbol_expr.symbol;
- VariableTableEntry *var = find_variable(g, block_context, name);
- if (var) {
- if (var->src_is_const) {
- add_node_error(g, lhs_node, buf_sprintf("cannot assign to constant"));
- expected_rhs_type = g->builtin_types.entry_invalid;
- } else {
- expected_rhs_type = var->type;
- get_resolved_expr(lhs_node)->variable = var;
- }
- } else {
- add_node_error(g, lhs_node,
- buf_sprintf("use of undeclared identifier '%s'", buf_ptr(name)));
- expected_rhs_type = g->builtin_types.entry_invalid;
- }
- }
- } else if (lhs_node->type == NodeTypeArrayAccessExpr) {
- expected_rhs_type = analyze_array_access_expr(g, import, block_context, lhs_node, purpose);
- } else if (lhs_node->type == NodeTypeFieldAccessExpr) {
- expected_rhs_type = analyze_field_access_expr(g, import, block_context, nullptr, lhs_node);
- } else if (lhs_node->type == NodeTypePrefixOpExpr &&
- lhs_node->data.prefix_op_expr.prefix_op == PrefixOpDereference)
- {
- assert(purpose == LValPurposeAssign);
- AstNode *target_node = lhs_node->data.prefix_op_expr.primary_expr;
- TypeTableEntry *type_entry = analyze_expression(g, import, block_context, nullptr, target_node);
- if (type_entry->id == TypeTableEntryIdInvalid) {
- expected_rhs_type = type_entry;
- } else if (type_entry->id == TypeTableEntryIdPointer) {
- expected_rhs_type = type_entry->data.pointer.child_type;
- } else {
- add_node_error(g, target_node,
- buf_sprintf("indirection requires pointer operand ('%s' invalid)",
- buf_ptr(&type_entry->name)));
- expected_rhs_type = g->builtin_types.entry_invalid;
- }
- } else {
- if (purpose == LValPurposeAssign) {
- add_node_error(g, lhs_node, buf_sprintf("invalid assignment target"));
- expected_rhs_type = g->builtin_types.entry_invalid;
- } else if (purpose == LValPurposeAddressOf) {
- TypeTableEntry *type_entry = analyze_expression(g, import, block_context, nullptr, lhs_node);
- if (type_entry->id == TypeTableEntryIdInvalid) {
- expected_rhs_type = g->builtin_types.entry_invalid;
- } else if (type_entry->id == TypeTableEntryIdMetaType) {
- expected_rhs_type = type_entry;
- } else {
- add_node_error(g, lhs_node, buf_sprintf("invalid addressof target"));
- expected_rhs_type = g->builtin_types.entry_invalid;
- }
- }
- }
- assert(expected_rhs_type);
- return expected_rhs_type;
-}
-
-static TypeTableEntry *analyze_bool_bin_op_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
- AstNode *node)
-{
- assert(node->type == NodeTypeBinOpExpr);
- BinOpType bin_op_type = node->data.bin_op_expr.bin_op;
-
- AstNode **op1 = &node->data.bin_op_expr.op1;
- AstNode **op2 = &node->data.bin_op_expr.op2;
- TypeTableEntry *op1_type = analyze_expression(g, import, context, nullptr, *op1);
- TypeTableEntry *op2_type = analyze_expression(g, import, context, nullptr, *op2);
-
- AstNode *op_nodes[] = {*op1, *op2};
- TypeTableEntry *op_types[] = {op1_type, op2_type};
-
- TypeTableEntry *resolved_type = resolve_peer_type_compatibility(g, import, context, node,
- op_nodes, op_types, 2);
-
- bool is_equality_cmp = (bin_op_type == BinOpTypeCmpEq || bin_op_type == BinOpTypeCmpNotEq);
-
- switch (resolved_type->id) {
- case TypeTableEntryIdInvalid:
- return g->builtin_types.entry_invalid;
-
- case TypeTableEntryIdNumLitFloat:
- case TypeTableEntryIdNumLitInt:
- case TypeTableEntryIdInt:
- case TypeTableEntryIdFloat:
- break;
-
- case TypeTableEntryIdBool:
- case TypeTableEntryIdMetaType:
- case TypeTableEntryIdVoid:
- case TypeTableEntryIdPointer:
- case TypeTableEntryIdPureError:
- case TypeTableEntryIdFn:
- case TypeTableEntryIdTypeDecl:
- case TypeTableEntryIdNamespace:
- case TypeTableEntryIdBlock:
- case TypeTableEntryIdGenericFn:
- if (!is_equality_cmp) {
- add_node_error(g, node,
- buf_sprintf("operator not allowed for type '%s'", buf_ptr(&resolved_type->name)));
- return g->builtin_types.entry_invalid;
- }
- break;
-
- case TypeTableEntryIdEnum:
- if (!is_equality_cmp || resolved_type->data.enumeration.gen_field_count != 0) {
- add_node_error(g, node,
- buf_sprintf("operator not allowed for type '%s'", buf_ptr(&resolved_type->name)));
- return g->builtin_types.entry_invalid;
- }
- break;
-
- case TypeTableEntryIdUnreachable:
- case TypeTableEntryIdArray:
- case TypeTableEntryIdStruct:
- case TypeTableEntryIdUndefLit:
- case TypeTableEntryIdNullLit:
- case TypeTableEntryIdMaybe:
- case TypeTableEntryIdErrorUnion:
- case TypeTableEntryIdUnion:
- add_node_error(g, node,
- buf_sprintf("operator not allowed for type '%s'", buf_ptr(&resolved_type->name)));
- return g->builtin_types.entry_invalid;
-
- case TypeTableEntryIdVar:
- zig_unreachable();
- }
-
- ConstExprValue *op1_val = &get_resolved_expr(*op1)->const_val;
- ConstExprValue *op2_val = &get_resolved_expr(*op2)->const_val;
- if (!op1_val->ok || !op2_val->ok) {
- return g->builtin_types.entry_bool;
- }
-
-
- ConstExprValue *out_val = &get_resolved_expr(node)->const_val;
- eval_const_expr_bin_op(op1_val, op1_type, bin_op_type, op2_val, op2_type, out_val);
- return g->builtin_types.entry_bool;
-
-}
-
-static TypeTableEntry *analyze_logic_bin_op_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
- AstNode *node)
-{
- assert(node->type == NodeTypeBinOpExpr);
- BinOpType bin_op_type = node->data.bin_op_expr.bin_op;
-
- AstNode *op1 = node->data.bin_op_expr.op1;
- AstNode *op2 = node->data.bin_op_expr.op2;
- TypeTableEntry *op1_type = analyze_expression(g, import, context, g->builtin_types.entry_bool, op1);
- TypeTableEntry *op2_type = analyze_expression(g, import, context, g->builtin_types.entry_bool, op2);
-
- if (op1_type->id == TypeTableEntryIdInvalid ||
- op2_type->id == TypeTableEntryIdInvalid)
- {
- return g->builtin_types.entry_invalid;
- }
-
- ConstExprValue *op1_val = &get_resolved_expr(op1)->const_val;
- ConstExprValue *op2_val = &get_resolved_expr(op2)->const_val;
- if (!op1_val->ok || !op2_val->ok) {
- return g->builtin_types.entry_bool;
- }
-
- ConstExprValue *out_val = &get_resolved_expr(node)->const_val;
- eval_const_expr_bin_op(op1_val, op1_type, bin_op_type, op2_val, op2_type, out_val);
- return g->builtin_types.entry_bool;
-}
-
-static TypeTableEntry *analyze_array_mult(CodeGen *g, ImportTableEntry *import, BlockContext *context,
- TypeTableEntry *expected_type, AstNode *node)
-{
- assert(node->type == NodeTypeBinOpExpr);
- assert(node->data.bin_op_expr.bin_op == BinOpTypeArrayMult);
-
- AstNode **op1 = node->data.bin_op_expr.op1->parent_field;
- AstNode **op2 = node->data.bin_op_expr.op2->parent_field;
-
- TypeTableEntry *op1_type = analyze_expression(g, import, context, nullptr, *op1);
- TypeTableEntry *op2_type = analyze_expression(g, import, context, nullptr, *op2);
-
- if (op1_type->id == TypeTableEntryIdInvalid ||
- op2_type->id == TypeTableEntryIdInvalid)
- {
- return g->builtin_types.entry_invalid;
- }
-
- ConstExprValue *op1_val = &get_resolved_expr(*op1)->const_val;
- ConstExprValue *op2_val = &get_resolved_expr(*op2)->const_val;
-
- AstNode *bad_node;
- if (!op1_val->ok) {
- bad_node = *op1;
- } else if (!op2_val->ok) {
- bad_node = *op2;
- } else {
- bad_node = nullptr;
- }
- if (bad_node) {
- add_node_error(g, bad_node, buf_sprintf("array multiplication requires constant expression"));
- return g->builtin_types.entry_invalid;
- }
-
- if (op1_type->id != TypeTableEntryIdArray) {
- add_node_error(g, *op1,
- buf_sprintf("expected array type, got '%s'", buf_ptr(&op1_type->name)));
- return g->builtin_types.entry_invalid;
- }
-
- if (op2_type->id != TypeTableEntryIdNumLitInt &&
- op2_type->id != TypeTableEntryIdInt)
- {
- add_node_error(g, *op2, buf_sprintf("expected integer type, got '%s'", buf_ptr(&op2_type->name)));
- return g->builtin_types.entry_invalid;
- }
-
- if (op2_val->data.x_bignum.is_negative) {
- add_node_error(g, *op2, buf_sprintf("expected positive number"));
- return g->builtin_types.entry_invalid;
- }
-
- ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
- const_val->ok = true;
- const_val->depends_on_compile_var = op1_val->depends_on_compile_var || op2_val->depends_on_compile_var;
-
- TypeTableEntry *child_type = op1_type->data.array.child_type;
- BigNum old_array_len;
- bignum_init_unsigned(&old_array_len, op1_type->data.array.len);
-
- BigNum new_array_len;
- if (bignum_mul(&new_array_len, &old_array_len, &op2_val->data.x_bignum)) {
- add_node_error(g, node, buf_sprintf("operation results in overflow"));
- return g->builtin_types.entry_invalid;
- }
-
- uint64_t old_array_len_bare = op1_type->data.array.len;
- uint64_t operand_amt = op2_val->data.x_bignum.data.x_uint;
-
- uint64_t new_array_len_bare = new_array_len.data.x_uint;
- const_val->data.x_array.fields = allocate<ConstExprValue*>(new_array_len_bare);
-
- uint64_t i = 0;
- for (uint64_t x = 0; x < operand_amt; x += 1) {
- for (uint64_t y = 0; y < old_array_len_bare; y += 1) {
- const_val->data.x_array.fields[i] = op1_val->data.x_array.fields[y];
- i += 1;
- }
- }
-
- return get_array_type(g, child_type, new_array_len_bare);
-}
-
-static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
- TypeTableEntry *expected_type, AstNode *node)
-{
- assert(node->type == NodeTypeBinOpExpr);
- BinOpType bin_op_type = node->data.bin_op_expr.bin_op;
- switch (bin_op_type) {
- case BinOpTypeAssign:
- case BinOpTypeAssignTimes:
- case BinOpTypeAssignTimesWrap:
- case BinOpTypeAssignDiv:
- case BinOpTypeAssignMod:
- case BinOpTypeAssignPlus:
- case BinOpTypeAssignPlusWrap:
- case BinOpTypeAssignMinus:
- case BinOpTypeAssignMinusWrap:
- case BinOpTypeAssignBitShiftLeft:
- case BinOpTypeAssignBitShiftLeftWrap:
- case BinOpTypeAssignBitShiftRight:
- case BinOpTypeAssignBitAnd:
- case BinOpTypeAssignBitXor:
- case BinOpTypeAssignBitOr:
- case BinOpTypeAssignBoolAnd:
- case BinOpTypeAssignBoolOr:
- {
- AstNode *lhs_node = node->data.bin_op_expr.op1;
-
- TypeTableEntry *expected_rhs_type = analyze_lvalue(g, import, context, lhs_node,
- LValPurposeAssign, false);
- if (expected_rhs_type->id == TypeTableEntryIdInvalid) {
- return g->builtin_types.entry_invalid;
- } else if (!is_op_allowed(expected_rhs_type, node->data.bin_op_expr.bin_op)) {
- if (expected_rhs_type->id != TypeTableEntryIdInvalid) {
- add_node_error(g, lhs_node,
- buf_sprintf("operator not allowed for type '%s'",
- buf_ptr(&expected_rhs_type->name)));
- }
- }
-
- analyze_expression(g, import, context, expected_rhs_type, node->data.bin_op_expr.op2);
- // not const ok because expression has side effects
- return g->builtin_types.entry_void;
- }
- case BinOpTypeBoolOr:
- case BinOpTypeBoolAnd:
- return analyze_logic_bin_op_expr(g, import, context, node);
- case BinOpTypeCmpEq:
- case BinOpTypeCmpNotEq:
- case BinOpTypeCmpLessThan:
- case BinOpTypeCmpGreaterThan:
- case BinOpTypeCmpLessOrEq:
- case BinOpTypeCmpGreaterOrEq:
- return analyze_bool_bin_op_expr(g, import, context, node);
- case BinOpTypeBinOr:
- case BinOpTypeBinXor:
- case BinOpTypeBinAnd:
- case BinOpTypeBitShiftLeft:
- case BinOpTypeBitShiftLeftWrap:
- case BinOpTypeBitShiftRight:
- case BinOpTypeAdd:
- case BinOpTypeAddWrap:
- case BinOpTypeSub:
- case BinOpTypeSubWrap:
- case BinOpTypeMult:
- case BinOpTypeMultWrap:
- case BinOpTypeDiv:
- case BinOpTypeMod:
- {
- AstNode **op1 = node->data.bin_op_expr.op1->parent_field;
- AstNode **op2 = node->data.bin_op_expr.op2->parent_field;
- TypeTableEntry *lhs_type = analyze_expression(g, import, context, nullptr, *op1);
- TypeTableEntry *rhs_type = analyze_expression(g, import, context, nullptr, *op2);
-
- AstNode *op_nodes[] = {*op1, *op2};
- TypeTableEntry *op_types[] = {lhs_type, rhs_type};
-
- TypeTableEntry *resolved_type = resolve_peer_type_compatibility(g, import, context, node,
- op_nodes, op_types, 2);
-
- if (resolved_type->id == TypeTableEntryIdInvalid) {
- return resolved_type;
- }
-
- if (resolved_type->id == TypeTableEntryIdInt ||
- resolved_type->id == TypeTableEntryIdNumLitInt)
- {
- // int
- } else if ((resolved_type->id == TypeTableEntryIdFloat ||
- resolved_type->id == TypeTableEntryIdNumLitFloat) &&
- (bin_op_type == BinOpTypeAdd ||
- bin_op_type == BinOpTypeSub ||
- bin_op_type == BinOpTypeMult ||
- bin_op_type == BinOpTypeDiv ||
- bin_op_type == BinOpTypeMod))
- {
- // float
- } else {
- add_node_error(g, node, buf_sprintf("invalid operands to binary expression: '%s' and '%s'",
- buf_ptr(&lhs_type->name), buf_ptr(&rhs_type->name)));
- return g->builtin_types.entry_invalid;
- }
-
- ConstExprValue *op1_val = &get_resolved_expr(*op1)->const_val;
- ConstExprValue *op2_val = &get_resolved_expr(*op2)->const_val;
- if (!op1_val->ok || !op2_val->ok) {
- return resolved_type;
- }
-
- ConstExprValue *out_val = &get_resolved_expr(node)->const_val;
- int err;
- if ((err = eval_const_expr_bin_op(op1_val, resolved_type, bin_op_type,
- op2_val, resolved_type, out_val)))
- {
- if (err == ErrorDivByZero) {
- add_node_error(g, node, buf_sprintf("division by zero is undefined"));
- return g->builtin_types.entry_invalid;
- } else if (err == ErrorOverflow) {
- add_node_error(g, node, buf_sprintf("value cannot be represented in any integer type"));
- return g->builtin_types.entry_invalid;
- }
- return g->builtin_types.entry_invalid;
- }
-
- num_lit_fits_in_other_type(g, node, resolved_type);
- return resolved_type;
- }
- case BinOpTypeUnwrapMaybe:
- {
- AstNode *op1 = node->data.bin_op_expr.op1;
- AstNode *op2 = node->data.bin_op_expr.op2;
- TypeTableEntry *lhs_type = analyze_expression(g, import, context, nullptr, op1);
-
- if (lhs_type->id == TypeTableEntryIdInvalid) {
- return lhs_type;
- } else if (lhs_type->id == TypeTableEntryIdMaybe) {
- TypeTableEntry *child_type = lhs_type->data.maybe.child_type;
- analyze_expression(g, import, context, child_type, op2);
- return child_type;
- } else {
- add_node_error(g, op1,
- buf_sprintf("expected maybe type, got '%s'",
- buf_ptr(&lhs_type->name)));
- return g->builtin_types.entry_invalid;
- }
- }
- case BinOpTypeArrayCat:
- {
- AstNode **op1 = node->data.bin_op_expr.op1->parent_field;
- AstNode **op2 = node->data.bin_op_expr.op2->parent_field;
-
- TypeTableEntry *op1_type = analyze_expression(g, import, context, nullptr, *op1);
- TypeTableEntry *child_type;
- if (op1_type->id == TypeTableEntryIdInvalid) {
- return g->builtin_types.entry_invalid;
- } else if (op1_type->id == TypeTableEntryIdArray) {
- child_type = op1_type->data.array.child_type;
- } else if (op1_type->id == TypeTableEntryIdPointer &&
- op1_type->data.pointer.child_type == g->builtin_types.entry_u8) {
- child_type = op1_type->data.pointer.child_type;
- } else {
- add_node_error(g, *op1, buf_sprintf("expected array or C string literal, got '%s'",
- buf_ptr(&op1_type->name)));
- return g->builtin_types.entry_invalid;
- }
-
- TypeTableEntry *op2_type = analyze_expression(g, import, context, nullptr, *op2);
-
- if (op2_type->id == TypeTableEntryIdInvalid) {
- return g->builtin_types.entry_invalid;
- } else if (op2_type->id == TypeTableEntryIdArray) {
- if (op2_type->data.array.child_type != child_type) {
- add_node_error(g, *op2, buf_sprintf("expected array of type '%s', got '%s'",
- buf_ptr(&child_type->name),
- buf_ptr(&op2_type->name)));
- return g->builtin_types.entry_invalid;
- }
- } else if (op2_type->id == TypeTableEntryIdPointer &&
- op2_type->data.pointer.child_type == g->builtin_types.entry_u8) {
- } else {
- add_node_error(g, *op2, buf_sprintf("expected array or C string literal, got '%s'",
- buf_ptr(&op2_type->name)));
- return g->builtin_types.entry_invalid;
- }
-
- ConstExprValue *op1_val = &get_resolved_expr(*op1)->const_val;
- ConstExprValue *op2_val = &get_resolved_expr(*op2)->const_val;
-
- AstNode *bad_node;
- if (!op1_val->ok) {
- bad_node = *op1;
- } else if (!op2_val->ok) {
- bad_node = *op2;
- } else {
- bad_node = nullptr;
- }
- if (bad_node) {
- add_node_error(g, bad_node, buf_sprintf("array concatenation requires constant expression"));
- return g->builtin_types.entry_invalid;
- }
-
- ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
- const_val->ok = true;
- const_val->depends_on_compile_var = op1_val->depends_on_compile_var ||
- op2_val->depends_on_compile_var;
-
- if (op1_type->id == TypeTableEntryIdArray) {
- uint64_t new_len = op1_type->data.array.len + op2_type->data.array.len;
- const_val->data.x_array.fields = allocate<ConstExprValue*>(new_len);
- uint64_t next_index = 0;
- for (uint64_t i = 0; i < op1_type->data.array.len; i += 1, next_index += 1) {
- const_val->data.x_array.fields[next_index] = op1_val->data.x_array.fields[i];
- }
- for (uint64_t i = 0; i < op2_type->data.array.len; i += 1, next_index += 1) {
- const_val->data.x_array.fields[next_index] = op2_val->data.x_array.fields[i];
- }
- return get_array_type(g, child_type, new_len);
- } else if (op1_type->id == TypeTableEntryIdPointer) {
- if (!op1_val->data.x_ptr.is_c_str) {
- add_node_error(g, *op1,
- buf_sprintf("expected array or C string literal, got '%s'",
- buf_ptr(&op1_type->name)));
- return g->builtin_types.entry_invalid;
- } else if (!op2_val->data.x_ptr.is_c_str) {
- add_node_error(g, *op2,
- buf_sprintf("expected array or C string literal, got '%s'",
- buf_ptr(&op2_type->name)));
- return g->builtin_types.entry_invalid;
- }
- const_val->data.x_ptr.is_c_str = true;
- const_val->data.x_ptr.len = op1_val->data.x_ptr.len + op2_val->data.x_ptr.len - 1;
- const_val->data.x_ptr.ptr = allocate<ConstExprValue*>(const_val->data.x_ptr.len);
- uint64_t next_index = 0;
- for (uint64_t i = 0; i < op1_val->data.x_ptr.len - 1; i += 1, next_index += 1) {
- const_val->data.x_ptr.ptr[next_index] = op1_val->data.x_ptr.ptr[i];
- }
- for (uint64_t i = 0; i < op2_val->data.x_ptr.len; i += 1, next_index += 1) {
- const_val->data.x_ptr.ptr[next_index] = op2_val->data.x_ptr.ptr[i];
- }
- return op1_type;
- } else {
- zig_unreachable();
- }
- }
- case BinOpTypeArrayMult:
- return analyze_array_mult(g, import, context, expected_type, node);
- case BinOpTypeInvalid:
- zig_unreachable();
- }
- zig_unreachable();
-}
-
-// Set name to nullptr to make the variable anonymous (not visible to programmer).
-// TODO merge with definition of add_local_var in ir.cpp
-static VariableTableEntry *add_local_var_shadowable(CodeGen *g, AstNode *source_node, ImportTableEntry *import,
- BlockContext *context, Buf *name, TypeTableEntry *type_entry, bool is_const, AstNode *val_node,
- bool shadowable)
-{
- VariableTableEntry *variable_entry = allocate<VariableTableEntry>(1);
- variable_entry->type = type_entry;
- variable_entry->block_context = context;
- variable_entry->import = import;
- variable_entry->shadowable = shadowable;
- variable_entry->mem_slot_index = SIZE_MAX;
-
- if (name) {
- buf_init_from_buf(&variable_entry->name, name);
-
- if (type_entry->id != TypeTableEntryIdInvalid) {
- VariableTableEntry *existing_var = find_variable(g, context, name);
- if (existing_var && !existing_var->shadowable) {
- ErrorMsg *msg = add_node_error(g, source_node,
- buf_sprintf("redeclaration of variable '%s'", buf_ptr(name)));
- add_error_note(g, msg, existing_var->decl_node, buf_sprintf("previous declaration is here"));
- variable_entry->type = g->builtin_types.entry_invalid;
- } else {
- auto primitive_table_entry = g->primitive_type_table.maybe_get(name);
- if (primitive_table_entry) {
- TypeTableEntry *type = primitive_table_entry->value;
- add_node_error(g, source_node,
- buf_sprintf("variable shadows type '%s'", buf_ptr(&type->name)));
- variable_entry->type = g->builtin_types.entry_invalid;
- } else {
- AstNode *decl_node = find_decl(context, name);
- if (decl_node && decl_node->type != NodeTypeVariableDeclaration) {
- ErrorMsg *msg = add_node_error(g, source_node,
- buf_sprintf("redefinition of '%s'", buf_ptr(name)));
- add_error_note(g, msg, decl_node, buf_sprintf("previous definition is here"));
- variable_entry->type = g->builtin_types.entry_invalid;
- }
- }
- }
- }
-
- context->var_table.put(&variable_entry->name, variable_entry);
- } else {
- // TODO replace _anon with @anon and make sure all tests still pass
- buf_init_from_str(&variable_entry->name, "_anon");
- }
- if (context->fn_entry) {
- context->fn_entry->variable_list.append(variable_entry);
- }
-
- variable_entry->src_is_const = is_const;
- variable_entry->gen_is_const = is_const;
- variable_entry->decl_node = source_node;
- variable_entry->val_node = val_node;
-
-
- return variable_entry;
-}
-
-static VariableTableEntry *add_local_var(CodeGen *g, AstNode *source_node, ImportTableEntry *import,
- BlockContext *context, Buf *name, TypeTableEntry *type_entry, bool is_const, AstNode *val_node)
-{
- return add_local_var_shadowable(g, source_node, import, context, name, type_entry, is_const, val_node, false);
-}
-
-static TypeTableEntry *analyze_unwrap_error_expr(CodeGen *g, ImportTableEntry *import,
- BlockContext *parent_context, TypeTableEntry *expected_type, AstNode *node)
-{
- AstNode *op1 = node->data.unwrap_err_expr.op1;
- AstNode *op2 = node->data.unwrap_err_expr.op2;
- AstNode *var_node = node->data.unwrap_err_expr.symbol;
-
- TypeTableEntry *lhs_type = analyze_expression(g, import, parent_context, nullptr, op1);
- if (lhs_type->id == TypeTableEntryIdInvalid) {
- return lhs_type;
- } else if (lhs_type->id == TypeTableEntryIdErrorUnion) {
- TypeTableEntry *child_type = lhs_type->data.error.child_type;
- BlockContext *child_context;
- if (var_node) {
- child_context = new_block_context(node, parent_context);
- var_node->block_context = child_context;
- Buf *var_name = var_node->data.symbol_expr.symbol;
- node->data.unwrap_err_expr.var = add_local_var(g, var_node, import, child_context, var_name,
- g->builtin_types.entry_pure_error, true, nullptr);
- } else {
- child_context = parent_context;
- }
-
- analyze_expression(g, import, child_context, child_type, op2);
- return child_type;
- } else {
- add_node_error(g, op1,
- buf_sprintf("expected error type, got '%s'", buf_ptr(&lhs_type->name)));
- return g->builtin_types.entry_invalid;
- }
-}
-
-
-static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTableEntry *import,
- BlockContext *context, AstNode *source_node,
- AstNodeVariableDeclaration *variable_declaration,
- bool expr_is_maybe, AstNode *decl_node, bool var_is_ptr)
-{
- bool is_const = variable_declaration->is_const;
- bool is_export = (variable_declaration->top_level_decl.visib_mod == VisibModExport);
- bool is_extern = variable_declaration->is_extern;
-
- TypeTableEntry *explicit_type = nullptr;
- if (variable_declaration->type != nullptr) {
- explicit_type = analyze_type_expr(g, import, context, variable_declaration->type);
- if (explicit_type->id == TypeTableEntryIdUnreachable) {
- add_node_error(g, variable_declaration->type,
- buf_sprintf("variable of type 'unreachable' not allowed"));
- explicit_type = g->builtin_types.entry_invalid;
- }
- }
-
- TypeTableEntry *implicit_type = nullptr;
- if (explicit_type && explicit_type->id == TypeTableEntryIdInvalid) {
- implicit_type = explicit_type;
- } else if (variable_declaration->expr) {
- implicit_type = analyze_expression(g, import, context, explicit_type, variable_declaration->expr);
- if (implicit_type->id == TypeTableEntryIdInvalid) {
- // ignore the poison value
- } else if (expr_is_maybe) {
- if (implicit_type->id == TypeTableEntryIdMaybe) {
- if (var_is_ptr) {
- // TODO if the expression is constant, can't get pointer to it
- implicit_type = get_pointer_to_type(g, implicit_type->data.maybe.child_type, false);
- } else {
- implicit_type = implicit_type->data.maybe.child_type;
- }
- } else {
- add_node_error(g, variable_declaration->expr, buf_sprintf("expected maybe type"));
- implicit_type = g->builtin_types.entry_invalid;
- }
- } else if (implicit_type->id == TypeTableEntryIdUnreachable) {
- add_node_error(g, source_node,
- buf_sprintf("variable initialization is unreachable"));
- implicit_type = g->builtin_types.entry_invalid;
- } else if ((!is_const || is_export) &&
- (implicit_type->id == TypeTableEntryIdNumLitFloat ||
- implicit_type->id == TypeTableEntryIdNumLitInt))
- {
- add_node_error(g, source_node, buf_sprintf("unable to infer variable type"));
- implicit_type = g->builtin_types.entry_invalid;
- } else if (implicit_type->id == TypeTableEntryIdMetaType && !is_const) {
- add_node_error(g, source_node, buf_sprintf("variable of type 'type' must be constant"));
- implicit_type = g->builtin_types.entry_invalid;
- }
- if (implicit_type->id != TypeTableEntryIdInvalid && !context->fn_entry) {
- ConstExprValue *const_val = &get_resolved_expr(variable_declaration->expr)->const_val;
- if (!const_val->ok) {
- add_node_error(g, first_executing_node(variable_declaration->expr),
- buf_sprintf("global variable initializer requires constant expression"));
- }
- }
- } else if (!is_extern) {
- add_node_error(g, source_node, buf_sprintf("variables must be initialized"));
- implicit_type = g->builtin_types.entry_invalid;
- }
-
- TypeTableEntry *type = explicit_type != nullptr ? explicit_type : implicit_type;
- assert(type != nullptr); // should have been caught by the parser
-
- VariableTableEntry *var = add_local_var(g, source_node, import, context,
- variable_declaration->symbol, type, is_const,
- expr_is_maybe ? nullptr : variable_declaration->expr);
-
- variable_declaration->variable = var;
-
- return var;
-}
-
-static VariableTableEntry *analyze_variable_declaration(CodeGen *g, ImportTableEntry *import,
- BlockContext *context, TypeTableEntry *expected_type, AstNode *node)
-{
- AstNodeVariableDeclaration *variable_declaration = &node->data.variable_declaration;
- return analyze_variable_declaration_raw(g, import, context, node, variable_declaration,
- false, nullptr, false);
-}
-
-static TypeTableEntry *analyze_null_literal_expr(CodeGen *g, ImportTableEntry *import,
- BlockContext *block_context, TypeTableEntry *expected_type, AstNode *node)
-{
- assert(node->type == NodeTypeNullLiteral);
-
- ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
- const_val->ok = true;
-
- return g->builtin_types.entry_null;
-}
-
-static TypeTableEntry *analyze_undefined_literal_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
- TypeTableEntry *expected_type, AstNode *node)
-{
- assert(node->type == NodeTypeUndefinedLiteral);
-
- Expr *expr = get_resolved_expr(node);
- ConstExprValue *const_val = &expr->const_val;
-
- const_val->ok = true;
- const_val->special = ConstValSpecialUndef;
-
- return expected_type ? expected_type : g->builtin_types.entry_undef;
-}
-
-static TypeTableEntry *analyze_zeroes_literal_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
- TypeTableEntry *expected_type, AstNode *node)
-{
- Expr *expr = get_resolved_expr(node);
- ConstExprValue *const_val = &expr->const_val;
-
- const_val->ok = true;
- const_val->special = ConstValSpecialZeroes;
-
- return expected_type ? expected_type : g->builtin_types.entry_undef;
-}
-
-static TypeTableEntry *analyze_number_literal_expr(CodeGen *g, ImportTableEntry *import,
- BlockContext *block_context, TypeTableEntry *expected_type, AstNode *node)
-{
- return resolve_expr_const_val_as_bignum(g, node, expected_type, node->data.number_literal.bignum, false);
-}
-
-static TypeTableEntry *analyze_array_type(CodeGen *g, ImportTableEntry *import, BlockContext *context,
- TypeTableEntry *expected_type, AstNode *node)
-{
- AstNode *size_node = node->data.array_type.size;
-
- TypeTableEntry *child_type = analyze_type_expr_pointer_only(g, import, context,
- node->data.array_type.child_type, true);
-
- if (child_type->id == TypeTableEntryIdUnreachable) {
- add_node_error(g, node, buf_create_from_str("array of unreachable not allowed"));
- return g->builtin_types.entry_invalid;
- } else if (child_type->id == TypeTableEntryIdInvalid) {
- return g->builtin_types.entry_invalid;
- }
-
- if (size_node) {
- child_type = analyze_type_expr(g, import, context, node->data.array_type.child_type);
- TypeTableEntry *size_type = analyze_expression(g, import, context,
- g->builtin_types.entry_usize, size_node);
- if (size_type->id == TypeTableEntryIdInvalid) {
- return g->builtin_types.entry_invalid;
- }
-
- ConstExprValue *const_val = &get_resolved_expr(size_node)->const_val;
- if (const_val->ok) {
- if (const_val->data.x_bignum.is_negative) {
- add_node_error(g, size_node,
- buf_sprintf("array size %s is negative",
- buf_ptr(bignum_to_buf(&const_val->data.x_bignum))));
- return g->builtin_types.entry_invalid;
- } else {
- return resolve_expr_const_val_as_type(g, node,
- get_array_type(g, child_type, const_val->data.x_bignum.data.x_uint), false);
- }
- } else if (context->fn_entry) {
- return resolve_expr_const_val_as_type(g, node,
- get_slice_type(g, child_type, node->data.array_type.is_const), false);
- } else {
- add_node_error(g, first_executing_node(size_node),
- buf_sprintf("unable to evaluate constant expression"));
- return g->builtin_types.entry_invalid;
- }
- } else {
- TypeTableEntry *slice_type = get_slice_type(g, child_type, node->data.array_type.is_const);
- return resolve_expr_const_val_as_type(g, node, slice_type, false);
- }
-}
-
-static TypeTableEntry *analyze_fn_proto_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
- TypeTableEntry *expected_type, AstNode *node)
-{
- TypeTableEntry *type_entry = analyze_fn_proto_type(g, import, context, expected_type, node,
- false, false, nullptr);
-
- if (type_entry->id == TypeTableEntryIdInvalid) {
- return type_entry;
- }
-
- return resolve_expr_const_val_as_type(g, node, type_entry, false);
-}
-
-static TypeTableEntry *analyze_while_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
- TypeTableEntry *expected_type, AstNode *node)
-{
- assert(node->type == NodeTypeWhileExpr);
-
- AstNode **condition_node = &node->data.while_expr.condition;
- AstNode *while_body_node = node->data.while_expr.body;
- AstNode **continue_expr_node = &node->data.while_expr.continue_expr;
-
- TypeTableEntry *condition_type = analyze_expression(g, import, context,
- g->builtin_types.entry_bool, *condition_node);
-
- if (*continue_expr_node) {
- analyze_expression(g, import, context, g->builtin_types.entry_void, *continue_expr_node);
- }
-
- BlockContext *child_context = new_block_context(node, context);
- child_context->parent_loop_node = node;
-
- analyze_expression(g, import, child_context, g->builtin_types.entry_void, while_body_node);
-
-
- TypeTableEntry *expr_return_type = g->builtin_types.entry_void;
-
- if (condition_type->id == TypeTableEntryIdInvalid) {
- expr_return_type = g->builtin_types.entry_invalid;
- } else {
- // if the condition is a simple constant expression and there are no break statements
- // then the return type is unreachable
- ConstExprValue *const_val = &get_resolved_expr(*condition_node)->const_val;
- if (const_val->ok) {
- if (const_val->data.x_bool) {
- node->data.while_expr.condition_always_true = true;
- if (!node->data.while_expr.contains_break) {
- expr_return_type = g->builtin_types.entry_unreachable;
- }
- }
- }
- }
-
- return expr_return_type;
-}
-
-static TypeTableEntry *analyze_break_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
- TypeTableEntry *expected_type, AstNode *node)
-{
- assert(node->type == NodeTypeBreak);
-
- AstNode *loop_node = context->parent_loop_node;
- if (loop_node) {
- if (loop_node->type == NodeTypeWhileExpr) {
- loop_node->data.while_expr.contains_break = true;
- } else if (loop_node->type == NodeTypeForExpr) {
- loop_node->data.for_expr.contains_break = true;
- } else {
- zig_unreachable();
- }
- } else {
- add_node_error(g, node, buf_sprintf("'break' expression outside loop"));
- }
- return g->builtin_types.entry_unreachable;
-}
-
-static TypeTableEntry *analyze_continue_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
- TypeTableEntry *expected_type, AstNode *node)
-{
- AstNode *loop_node = context->parent_loop_node;
- if (loop_node) {
- if (loop_node->type == NodeTypeWhileExpr) {
- loop_node->data.while_expr.contains_continue = true;
- } else if (loop_node->type == NodeTypeForExpr) {
- loop_node->data.for_expr.contains_continue = true;
- } else {
- zig_unreachable();
- }
- } else {
- add_node_error(g, node, buf_sprintf("'continue' expression outside loop"));
- }
- return g->builtin_types.entry_unreachable;
-}
-
-static TypeTableEntry *add_error_if_type_is_num_lit(CodeGen *g, TypeTableEntry *type_entry, AstNode *source_node) {
- if (type_entry->id == TypeTableEntryIdNumLitInt ||
- type_entry->id == TypeTableEntryIdNumLitFloat)
- {
- add_node_error(g, source_node, buf_sprintf("unable to infer expression type"));
- return g->builtin_types.entry_invalid;
- } else {
- return type_entry;
- }
-}
-
-static TypeTableEntry *analyze_if(CodeGen *g, ImportTableEntry *import, BlockContext *parent_context,
- TypeTableEntry *expected_type, AstNode *node,
- AstNode **then_node, AstNode **else_node, bool cond_is_const, bool cond_bool_val)
-{
- if (!*else_node) {
- *else_node = create_ast_void_node(g, import, node);
- normalize_parent_ptrs(node);
- }
-
- BlockContext *then_context;
- BlockContext *else_context;
- if (cond_is_const) {
- if (cond_bool_val) {
- then_context = parent_context;
- else_context = new_block_context(node, parent_context);
-
- else_context->codegen_excluded = true;
- } else {
- then_context = new_block_context(node, parent_context);
- else_context = parent_context;
-
- then_context->codegen_excluded = true;
- }
- } else {
- then_context = parent_context;
- else_context = parent_context;
- }
-
- TypeTableEntry *then_type = nullptr;
- TypeTableEntry *else_type = nullptr;
-
- if (!then_context->codegen_excluded) {
- then_type = analyze_expression(g, import, then_context, expected_type, *then_node);
- if (then_type->id == TypeTableEntryIdInvalid) {
- return g->builtin_types.entry_invalid;
- }
- }
- if (!else_context->codegen_excluded) {
- else_type = analyze_expression(g, import, else_context, expected_type, *else_node);
- if (else_type->id == TypeTableEntryIdInvalid) {
- return g->builtin_types.entry_invalid;
- }
- }
-
- TypeTableEntry *result_type;
- if (then_context->codegen_excluded) {
- result_type = else_type;
- } else if (else_context->codegen_excluded) {
- result_type = then_type;
- } else if (expected_type) {
- result_type = (then_type->id == TypeTableEntryIdUnreachable) ? else_type : then_type;
- } else {
- AstNode *op_nodes[] = {*then_node, *else_node};
- TypeTableEntry *op_types[] = {then_type, else_type};
- result_type = resolve_peer_type_compatibility(g, import, parent_context, node, op_nodes, op_types, 2);
- }
-
- if (!cond_is_const) {
- return add_error_if_type_is_num_lit(g, result_type, node);
- }
-
- ConstExprValue *other_const_val;
- if (cond_bool_val) {
- other_const_val = &get_resolved_expr(*then_node)->const_val;
- } else {
- other_const_val = &get_resolved_expr(*else_node)->const_val;
- }
- if (!other_const_val->ok) {
- return add_error_if_type_is_num_lit(g, result_type, node);
- }
-
- ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
- *const_val = *other_const_val;
- // the condition depends on a compile var, so the entire if statement does too
- const_val->depends_on_compile_var = true;
- return result_type;
-}
-
-static TypeTableEntry *analyze_if_bool_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
- TypeTableEntry *expected_type, AstNode *node)
-{
- AstNode **cond = &node->data.if_bool_expr.condition;
- TypeTableEntry *cond_type = analyze_expression(g, import, context, g->builtin_types.entry_bool, *cond);
-
- if (cond_type->id == TypeTableEntryIdInvalid) {
- return cond_type;
- }
-
- ConstExprValue *cond_val = &get_resolved_expr(*cond)->const_val;
- if (cond_val->special == ConstValSpecialUndef) {
- add_node_error(g, first_executing_node(*cond), buf_sprintf("branch on undefined value"));
- return cond_type;
- }
- if (cond_val->ok && !cond_val->depends_on_compile_var) {
- const char *str_val = cond_val->data.x_bool ? "true" : "false";
- add_node_error(g, first_executing_node(*cond),
- buf_sprintf("condition is always %s; unnecessary if statement", str_val));
- }
-
- bool cond_is_const = cond_val->ok;
- bool cond_bool_val = cond_val->data.x_bool;
-
- AstNode **then_node = &node->data.if_bool_expr.then_block;
- AstNode **else_node = &node->data.if_bool_expr.else_node;
-
- return analyze_if(g, import, context, expected_type, node,
- then_node, else_node, cond_is_const, cond_bool_val);
-}
-
-static TypeTableEntry *analyze_if_var_expr(CodeGen *g, ImportTableEntry *import, BlockContext *parent_context,
- TypeTableEntry *expected_type, AstNode *node)
-{
- assert(node->type == NodeTypeIfVarExpr);
-
- BlockContext *child_context = new_block_context(node, parent_context);
-
- analyze_variable_declaration_raw(g, import, child_context, node, &node->data.if_var_expr.var_decl, true,
- nullptr, node->data.if_var_expr.var_is_ptr);
- VariableTableEntry *var = node->data.if_var_expr.var_decl.variable;
- if (var->type->id == TypeTableEntryIdInvalid) {
- return g->builtin_types.entry_invalid;
- }
- AstNode *var_expr_node = node->data.if_var_expr.var_decl.expr;
- ConstExprValue *var_const_val = &get_resolved_expr(var_expr_node)->const_val;
- bool cond_is_const = var_const_val->ok;
- bool cond_bool_val = cond_is_const ? (var_const_val->data.x_maybe != nullptr) : false;
-
-
- AstNode **then_node = &node->data.if_var_expr.then_block;
- AstNode **else_node = &node->data.if_var_expr.else_node;
-
- return analyze_if(g, import, child_context, expected_type,
- node, then_node, else_node, cond_is_const, cond_bool_val);
-}
-
-bool type_is_codegen_pointer(TypeTableEntry *type) {
- if (type->id == TypeTableEntryIdPointer) return true;
- if (type->id == TypeTableEntryIdFn) return true;
- if (type->id == TypeTableEntryIdMaybe) {
- if (type->data.maybe.child_type->id == TypeTableEntryIdPointer) return true;
- if (type->data.maybe.child_type->id == TypeTableEntryIdFn) return true;
- }
- return false;
-}
-
-static TypeTableEntry *bad_method_call(CodeGen *g, AstNode *node, TypeTableEntry *container_type,
- TypeTableEntry *expected_param_type, FnTableEntry *fn_table_entry)
-{
- ErrorMsg *msg = add_node_error(g, node,
- buf_sprintf("function called as method of '%s', but first parameter is of type '%s'",
- buf_ptr(&container_type->name),
- buf_ptr(&expected_param_type->name)));
- if (fn_table_entry) {
- add_error_note(g, msg, fn_table_entry->proto_node, buf_sprintf("function declared here"));
- }
- return g->builtin_types.entry_invalid;
-}
-
-// 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)
-{
- assert(node->type == NodeTypeFnCallExpr);
-
- if (fn_type->id == TypeTableEntryIdInvalid) {
- return fn_type;
- }
-
- // 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;
-
- // count parameters
- size_t struct_node_1_or_0 = struct_node ? 1 : 0;
- size_t 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);
- size_t call_param_count = node->data.fn_call_expr.params.length;
- size_t expect_arg_count = src_param_count - struct_node_1_or_0;
-
- bool ok_invocation = true;
-
- if (fn_type->data.fn.fn_type_id.is_var_args) {
- if (call_param_count < expect_arg_count) {
- ok_invocation = false;
- add_node_error(g, node,
- buf_sprintf("expected at least %zu arguments, got %zu", src_param_count, call_param_count));
- }
- } else if (expect_arg_count != call_param_count) {
- ok_invocation = false;
- add_node_error(g, node,
- buf_sprintf("expected %zu arguments, got %zu", expect_arg_count, call_param_count));
- }
-
- bool all_args_const_expr = true;
-
- if (struct_node) {
- Expr *struct_expr = get_resolved_expr(struct_node);
- ConstExprValue *struct_const_val = &struct_expr->const_val;
- if (!struct_const_val->ok) {
- all_args_const_expr = false;
- }
-
- FnTypeParamInfo *param_info = &fn_type->data.fn.fn_type_id.param_info[0];
- TypeTableEntry *expected_param_type = param_info->type;
- TypeTableEntry *container_bare_type = container_ref_type(struct_expr->type_entry);
- if (is_container_ref(expected_param_type)) {
- TypeTableEntry *param_bare_type = container_ref_type(expected_param_type);
- if (param_bare_type != container_bare_type) {
- return bad_method_call(g, node, container_bare_type, expected_param_type, fn_table_entry);
- }
- } else {
- return bad_method_call(g, node, container_bare_type, expected_param_type, fn_table_entry);
- }
- }
-
- // 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.
- size_t next_type_i = struct_node_1_or_0;
- for (size_t call_i = 0; call_i < call_param_count; call_i += 1) {
- size_t 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;
- 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;
- }
-
- ConstExprValue *const_arg_val = &get_resolved_expr(*param_node)->const_val;
- if (!const_arg_val->ok) {
- all_args_const_expr = false;
- }
- }
-
- TypeTableEntry *return_type = fn_type->data.fn.fn_type_id.return_type;
-
- if (return_type->id == TypeTableEntryIdInvalid) {
- return return_type;
- }
-
- 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) {
- analyze_fn_body(g, fn_table_entry);
- if (fn_table_entry->proto_node->data.fn_proto.skip) {
- return g->builtin_types.entry_invalid;
- }
- }
- if (all_args_const_expr) {
- if (fn_table_entry->is_pure && fn_table_entry->anal_state == FnAnalStateComplete) {
- if (eval_fn(g, node, fn_table_entry, result_val, 1000, struct_node)) {
- // function evaluation generated an error
- return g->builtin_types.entry_invalid;
- }
- return return_type;
- }
- }
- }
- if (!ok_invocation || !fn_table_entry || !fn_table_entry->is_pure || fn_table_entry->want_pure == WantPureFalse) {
- // calling an impure fn is impure
- mark_impure_fn(g, context, node);
- if (fn_table_entry && fn_table_entry->want_pure == WantPureTrue) {
- return g->builtin_types.entry_invalid;
- }
- }
-
- // TODO
- //if (handle_is_ptr(return_type)) {
- // if (context->fn_entry) {
- // context->fn_entry->cast_alloca_list.append(node);
- // } else if (!result_val->ok) {
- // add_node_error(g, node, buf_sprintf("unable to evaluate constant expression"));
- // }
- //}
-
- return return_type;
-}
-
-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(call_node->type == NodeTypeFnCallExpr);
- assert(fn_table_entry);
-
- AstNode *decl_node = fn_table_entry->proto_node;
-
- // count parameters
- size_t struct_node_1_or_0 = (struct_node ? 1 : 0);
- size_t src_param_count = decl_node->data.fn_proto.params.length;
- size_t 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 %zu arguments, got %zu", src_param_count - struct_node_1_or_0, call_param_count));
- return g->builtin_types.entry_invalid;
- }
-
- size_t inline_or_var_type_arg_count = decl_node->data.fn_proto.inline_or_var_type_arg_count;
- assert(inline_or_var_type_arg_count > 0);
-
- BlockContext *child_context = decl_node->owner->block_context;
- size_t 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_or_var_type_arg_count;
- generic_fn_type_id->generic_params = allocate<GenericParamValue>(inline_or_var_type_arg_count);
-
- size_t next_impl_i = 0;
- for (size_t call_i = 0; call_i < call_param_count; call_i += 1) {
- size_t 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);
-
- 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;
- }
-
- bool is_var_type = (expected_param_type->id == TypeTableEntryIdVar);
- bool is_inline = generic_param_decl_node->data.param_decl.is_inline;
- if (!is_inline && !is_var_type) {
- next_impl_i += 1;
- continue;
- }
-
-
- AstNode **param_node = &call_node->data.fn_call_expr.params.at(call_i);
- TypeTableEntry *param_type = analyze_expression(g, import, parent_context,
- is_var_type ? nullptr : 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 (is_inline && !const_val->ok) {
- add_node_error(g, *param_node,
- buf_sprintf("unable to evaluate constant expression for inline parameter"));
-
- return g->builtin_types.entry_invalid;
- }
-
- VariableTableEntry *var = add_local_var_shadowable(g, generic_param_decl_node, decl_node->owner, child_context,
- generic_param_decl_node->data.param_decl.name, param_type, true, *param_node, true);
- // This generic function instance could be called with anything, so when this variable is read it
- // needs to know that it depends on compile time variable data.
- var->force_depends_on_compile_var = true;
-
- GenericParamValue *generic_param_value =
- &generic_fn_type_id->generic_params[next_generic_param_index];
- generic_param_value->type = param_type;
- generic_param_value->node = is_inline ? *param_node : nullptr;
- generic_param_value->impl_index = next_impl_i;
- next_generic_param_index += 1;
-
- if (!is_inline) {
- next_impl_i += 1;
- }
- }
-
- assert(next_generic_param_index == inline_or_var_type_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.inline_or_var_type_arg_count = 0;
- impl_decl_node->data.fn_proto.generic_proto_node = decl_node;
-
- // replace var arg types with actual types
- for (size_t generic_arg_i = 0; generic_arg_i < inline_or_var_type_arg_count; generic_arg_i += 1) {
- GenericParamValue *generic_param_value = &generic_fn_type_id->generic_params[generic_arg_i];
- if (!generic_param_value->node) {
- size_t impl_i = generic_param_value->impl_index;
- AstNode *impl_param_decl_node = impl_decl_node->data.fn_proto.params.at(impl_i);
- assert(impl_param_decl_node->type == NodeTypeParamDecl);
-
- impl_param_decl_node->data.param_decl.type = create_ast_type_node(g, import,
- generic_param_value->type, impl_param_decl_node);
- normalize_parent_ptrs(impl_param_decl_node);
- }
- }
-
- 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;
- }
-
- 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,
- TypeTableEntry *expected_type, AstNode *node, TypeTableEntry *generic_fn_type)
-{
- assert(node->type == NodeTypeFnCallExpr);
- assert(generic_fn_type->id == TypeTableEntryIdGenericFn);
-
- AstNode *decl_node = generic_fn_type->data.generic_fn.decl_node;
- assert(decl_node->type == NodeTypeContainerDecl);
- ZigList<AstNode *> *generic_params = &decl_node->data.struct_decl.generic_params;
-
- size_t expected_param_count = generic_params->length;
- size_t actual_param_count = node->data.fn_call_expr.params.length;
-
- if (actual_param_count != expected_param_count) {
- add_node_error(g, first_executing_node(node),
- buf_sprintf("expected %zu arguments, got %zu", expected_param_count, actual_param_count));
- return g->builtin_types.entry_invalid;
- }
-
- GenericFnTypeId *generic_fn_type_id = allocate<GenericFnTypeId>(1);
- generic_fn_type_id->decl_node = decl_node;
- generic_fn_type_id->generic_param_count = actual_param_count;
- generic_fn_type_id->generic_params = allocate<GenericParamValue>(actual_param_count);
-
- BlockContext *child_context = decl_node->owner->block_context;
- for (size_t i = 0; i < actual_param_count; i += 1) {
- AstNode *generic_param_decl_node = generic_params->at(i);
- assert(generic_param_decl_node->type == NodeTypeParamDecl);
-
- 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 = &node->data.fn_call_expr.params.at(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) {
- VariableTableEntry *var = 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);
- var->force_depends_on_compile_var = true;
- } else {
- add_node_error(g, *param_node, buf_sprintf("unable to evaluate constant expression"));
-
- return g->builtin_types.entry_invalid;
- }
-
- GenericParamValue *generic_param_value = &generic_fn_type_id->generic_params[i];
- generic_param_value->type = param_type;
- generic_param_value->node = *param_node;
- }
-
- auto entry = g->generic_table.maybe_get(generic_fn_type_id);
- if (entry) {
- AstNode *impl_decl_node = entry->value;
- assert(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);
- }
-
- // 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,
- TypeTableEntry *expected_type, AstNode *node)
-{
- AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr;
-
- if (node->data.fn_call_expr.is_builtin) {
- zig_panic("moved builtin fn call code to ir.cpp");
- }
-
- TypeTableEntry *invoke_type_entry = analyze_expression(g, import, context, nullptr, fn_ref_expr);
- if (invoke_type_entry->id == TypeTableEntryIdInvalid) {
- return g->builtin_types.entry_invalid;
- }
-
- // use constant expression evaluator to figure out the function at compile time.
- // otherwise we treat this as a function pointer.
- ConstExprValue *const_val = &get_resolved_expr(fn_ref_expr)->const_val;
-
- if (const_val->ok) {
- if (invoke_type_entry->id == TypeTableEntryIdMetaType) {
- zig_unreachable();
- } else if (invoke_type_entry->id == TypeTableEntryIdFn) {
- 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 = 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) {
- 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)));
- return g->builtin_types.entry_invalid;
- }
- }
-
- // function pointer
- if (invoke_type_entry->id == TypeTableEntryIdFn) {
- return analyze_fn_call_ptr(g, import, context, expected_type, node, invoke_type_entry, nullptr);
- } else {
- add_node_error(g, fn_ref_expr,
- buf_sprintf("type '%s' not a function", buf_ptr(&invoke_type_entry->name)));
- return g->builtin_types.entry_invalid;
- }
-}
-
-static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
- TypeTableEntry *expected_type, AstNode *node)
-{
- AstNode **expr_node = &node->data.switch_expr.expr;
- TypeTableEntry *expr_type = analyze_expression(g, import, context, nullptr, *expr_node);
- ConstExprValue *expr_val = &get_resolved_expr(*expr_node)->const_val;
- if (expr_val->ok && !expr_val->depends_on_compile_var) {
- add_node_error(g, first_executing_node(*expr_node),
- buf_sprintf("value is constant; unnecessary switch statement"));
- }
- ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
-
-
- size_t prong_count = node->data.switch_expr.prongs.length;
- AstNode **peer_nodes = allocate<AstNode*>(prong_count);
- TypeTableEntry **peer_types = allocate<TypeTableEntry*>(prong_count);
-
- bool any_errors = false;
- if (expr_type->id == TypeTableEntryIdInvalid) {
- return expr_type;
- } else if (expr_type->id == TypeTableEntryIdUnreachable) {
- add_node_error(g, first_executing_node(*expr_node),
- buf_sprintf("switch on unreachable expression not allowed"));
- return g->builtin_types.entry_invalid;
- }
-
-
- size_t *field_use_counts = nullptr;
- HashMap<int, AstNode *, int_hash, int_eq> err_use_nodes = {};
- if (expr_type->id == TypeTableEntryIdEnum) {
- field_use_counts = allocate<size_t>(expr_type->data.enumeration.src_field_count);
- } else if (expr_type->id == TypeTableEntryIdErrorUnion) {
- err_use_nodes.init(10);
- }
-
- size_t *const_chosen_prong_index = &node->data.switch_expr.const_chosen_prong_index;
- *const_chosen_prong_index = SIZE_MAX;
- AstNode *else_prong = nullptr;
- for (size_t prong_i = 0; prong_i < prong_count; prong_i += 1) {
- AstNode *prong_node = node->data.switch_expr.prongs.at(prong_i);
-
- TypeTableEntry *var_type;
- bool var_is_target_expr;
- if (prong_node->data.switch_prong.items.length == 0) {
- if (else_prong) {
- add_node_error(g, prong_node, buf_sprintf("multiple else prongs in switch expression"));
- any_errors = true;
- } else {
- else_prong = prong_node;
- }
- var_type = expr_type;
- var_is_target_expr = true;
- if (*const_chosen_prong_index == SIZE_MAX && expr_val->ok) {
- *const_chosen_prong_index = prong_i;
- }
- } else {
- bool all_agree_on_var_type = true;
- var_type = nullptr;
-
- for (size_t item_i = 0; item_i < prong_node->data.switch_prong.items.length; item_i += 1) {
- AstNode *item_node = prong_node->data.switch_prong.items.at(item_i);
- if (item_node->type == NodeTypeSwitchRange) {
- zig_panic("TODO range in switch statement");
- }
-
- if (expr_type->id == TypeTableEntryIdEnum) {
- if (item_node->type == NodeTypeSymbol) {
- Buf *field_name = item_node->data.symbol_expr.symbol;
- TypeEnumField *type_enum_field = find_enum_type_field(expr_type, field_name);
- if (type_enum_field) {
- item_node->data.symbol_expr.enum_field = type_enum_field;
- if (!var_type) {
- var_type = type_enum_field->type_entry;
- }
- if (type_enum_field->type_entry != var_type) {
- all_agree_on_var_type = false;
- }
- uint32_t field_index = type_enum_field->value;
- assert(field_use_counts);
- field_use_counts[field_index] += 1;
- if (field_use_counts[field_index] > 1) {
- add_node_error(g, item_node,
- buf_sprintf("duplicate switch value: '%s'",
- buf_ptr(type_enum_field->name)));
- any_errors = true;
- }
- if (!any_errors && expr_val->ok) {
- if (expr_val->data.x_enum.tag == type_enum_field->value) {
- *const_chosen_prong_index = prong_i;
- }
- }
- } else {
- add_node_error(g, item_node,
- buf_sprintf("enum '%s' has no field '%s'",
- buf_ptr(&expr_type->name), buf_ptr(field_name)));
- any_errors = true;
- }
- } else {
- add_node_error(g, item_node, buf_sprintf("expected enum tag name"));
- any_errors = true;
- }
- } else if (expr_type->id == TypeTableEntryIdErrorUnion) {
- if (item_node->type == NodeTypeSymbol) {
- Buf *err_name = item_node->data.symbol_expr.symbol;
- bool is_ok_case = buf_eql_str(err_name, "Ok");
- auto err_table_entry = is_ok_case ? nullptr: g->error_table.maybe_get(err_name);
- if (is_ok_case || err_table_entry) {
- uint32_t err_value = is_ok_case ? 0 : err_table_entry->value->value;
- item_node->data.symbol_expr.err_value = err_value;
- TypeTableEntry *this_var_type;
- if (is_ok_case) {
- this_var_type = expr_type->data.error.child_type;
- } else {
- this_var_type = g->builtin_types.entry_pure_error;
- }
- if (!var_type) {
- var_type = this_var_type;
- }
- if (this_var_type != var_type) {
- all_agree_on_var_type = false;
- }
-
- // detect duplicate switch values
- auto existing_entry = err_use_nodes.maybe_get(err_value);
- if (existing_entry) {
- add_node_error(g, existing_entry->value,
- buf_sprintf("duplicate switch value: '%s'", buf_ptr(err_name)));
- any_errors = true;
- } else {
- err_use_nodes.put(err_value, item_node);
- }
-
- if (!any_errors && expr_val->ok) {
- if (expr_val->data.x_err.err->value == err_value) {
- *const_chosen_prong_index = prong_i;
- }
- }
- } else {
- add_node_error(g, item_node,
- buf_sprintf("use of undeclared error value '%s'", buf_ptr(err_name)));
- any_errors = true;
- }
- } else {
- add_node_error(g, item_node, buf_sprintf("expected error value name"));
- any_errors = true;
- }
- } else {
- if (!any_errors && expr_val->ok) {
- // note: there is now a function in eval.cpp for doing const expr comparison
- zig_panic("TODO determine if const exprs are equal");
- }
- TypeTableEntry *item_type = analyze_expression(g, import, context, expr_type, item_node);
- if (item_type->id != TypeTableEntryIdInvalid) {
- ConstExprValue *const_val = &get_resolved_expr(item_node)->const_val;
- if (!const_val->ok) {
- add_node_error(g, item_node,
- buf_sprintf("unable to evaluate constant expression"));
- any_errors = true;
- }
- }
- }
- }
- if (!var_type || !all_agree_on_var_type) {
- var_type = expr_type;
- var_is_target_expr = true;
- } else {
- var_is_target_expr = false;
- }
- }
-
- BlockContext *child_context = new_block_context(node, context);
- prong_node->data.switch_prong.block_context = child_context;
- AstNode *var_node = prong_node->data.switch_prong.var_symbol;
- if (var_node) {
- assert(var_node->type == NodeTypeSymbol);
- Buf *var_name = var_node->data.symbol_expr.symbol;
- var_node->block_context = child_context;
- prong_node->data.switch_prong.var = add_local_var(g, var_node, import,
- child_context, var_name, var_type, true, nullptr);
- prong_node->data.switch_prong.var_is_target_expr = var_is_target_expr;
- }
- }
-
- for (size_t prong_i = 0; prong_i < prong_count; prong_i += 1) {
- AstNode *prong_node = node->data.switch_expr.prongs.at(prong_i);
- BlockContext *child_context = prong_node->data.switch_prong.block_context;
- child_context->codegen_excluded = expr_val->ok && (*const_chosen_prong_index != prong_i);
-
- if (child_context->codegen_excluded) {
- peer_types[prong_i] = g->builtin_types.entry_unreachable;
- } else {
- peer_types[prong_i] = analyze_expression(g, import, child_context, expected_type,
- prong_node->data.switch_prong.expr);
- }
- // This must go after the analyze_expression for
- // prong_node->data.switch_prong.expr because of AST rewriting.
- peer_nodes[prong_i] = prong_node->data.switch_prong.expr;
- }
-
- if (expr_type->id == TypeTableEntryIdEnum && !else_prong) {
- for (uint32_t i = 0; i < expr_type->data.enumeration.src_field_count; i += 1) {
- if (field_use_counts[i] == 0) {
- add_node_error(g, node,
- buf_sprintf("enumeration value '%s' not handled in switch",
- buf_ptr(expr_type->data.enumeration.fields[i].name)));
- any_errors = true;
- }
- }
- }
-
- if (any_errors) {
- return g->builtin_types.entry_invalid;
- }
-
- if (prong_count == 0) {
- add_node_error(g, node, buf_sprintf("switch statement has no prongs"));
- return g->builtin_types.entry_invalid;
- }
-
- TypeTableEntry *result_type = resolve_peer_type_compatibility(g, import, context, node,
- peer_nodes, peer_types, prong_count);
-
- if (expr_val->ok) {
- assert(*const_chosen_prong_index != SIZE_MAX);
-
- *const_val = get_resolved_expr(peer_nodes[*const_chosen_prong_index])->const_val;
- // the target expr depends on a compile var because we have an error on unnecessary
- // switch statement, so the entire switch statement does too
- const_val->depends_on_compile_var = true;
-
- if (!const_val->ok) {
- return add_error_if_type_is_num_lit(g, result_type, node);
- }
- } else {
- return add_error_if_type_is_num_lit(g, result_type, node);
- }
-
- return result_type;
-}
-
-static TypeTableEntry *analyze_return_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
- TypeTableEntry *expected_type, AstNode *node)
-{
- if (!node->data.return_expr.expr) {
- node->data.return_expr.expr = create_ast_void_node(g, import, node);
- normalize_parent_ptrs(node);
- }
-
- TypeTableEntry *expected_return_type = get_return_type(context);
-
- switch (node->data.return_expr.kind) {
- case ReturnKindUnconditional:
- zig_panic("TODO moved to ir.cpp");
- case ReturnKindError:
- {
- TypeTableEntry *expected_err_type;
- if (expected_type) {
- expected_err_type = get_error_type(g, expected_type);
- } else {
- expected_err_type = nullptr;
- }
- TypeTableEntry *resolved_type = analyze_expression(g, import, context, expected_err_type,
- node->data.return_expr.expr);
- if (resolved_type->id == TypeTableEntryIdInvalid) {
- return resolved_type;
- } else if (resolved_type->id == TypeTableEntryIdErrorUnion) {
- if (expected_return_type->id != TypeTableEntryIdErrorUnion &&
- expected_return_type->id != TypeTableEntryIdPureError)
- {
- ErrorMsg *msg = add_node_error(g, node,
- buf_sprintf("%%return statement in function with return type '%s'",
- buf_ptr(&expected_return_type->name)));
- AstNode *return_type_node = context->fn_entry->fn_def_node->data.fn_def.fn_proto->data.fn_proto.return_type;
- add_error_note(g, msg, return_type_node, buf_sprintf("function return type here"));
- }
-
- return resolved_type->data.error.child_type;
- } else {
- add_node_error(g, node->data.return_expr.expr,
- buf_sprintf("expected error type, got '%s'", buf_ptr(&resolved_type->name)));
- return g->builtin_types.entry_invalid;
- }
- }
- case ReturnKindMaybe:
- {
- TypeTableEntry *expected_maybe_type;
- if (expected_type) {
- expected_maybe_type = get_maybe_type(g, expected_type);
- } else {
- expected_maybe_type = nullptr;
- }
- TypeTableEntry *resolved_type = analyze_expression(g, import, context, expected_maybe_type,
- node->data.return_expr.expr);
- if (resolved_type->id == TypeTableEntryIdInvalid) {
- return resolved_type;
- } else if (resolved_type->id == TypeTableEntryIdMaybe) {
- if (expected_return_type->id != TypeTableEntryIdMaybe) {
- ErrorMsg *msg = add_node_error(g, node,
- buf_sprintf("?return statement in function with return type '%s'",
- buf_ptr(&expected_return_type->name)));
- AstNode *return_type_node = context->fn_entry->fn_def_node->data.fn_def.fn_proto->data.fn_proto.return_type;
- add_error_note(g, msg, return_type_node, buf_sprintf("function return type here"));
- }
-
- return resolved_type->data.maybe.child_type;
- } else {
- add_node_error(g, node->data.return_expr.expr,
- buf_sprintf("expected maybe type, got '%s'", buf_ptr(&resolved_type->name)));
- return g->builtin_types.entry_invalid;
- }
- }
- }
- zig_unreachable();
-}
-
-static void validate_voided_expr(CodeGen *g, AstNode *source_node, TypeTableEntry *type_entry) {
- if (type_entry->id == TypeTableEntryIdMetaType) {
- add_node_error(g, first_executing_node(source_node), buf_sprintf("expected expression, found type"));
- } else if (type_entry->id == TypeTableEntryIdErrorUnion) {
- add_node_error(g, first_executing_node(source_node), buf_sprintf("statement ignores error value"));
- }
-}
-
-static TypeTableEntry *analyze_defer(CodeGen *g, ImportTableEntry *import, BlockContext *parent_context,
- TypeTableEntry *expected_type, AstNode *node)
-{
- if (!parent_context->fn_entry) {
- add_node_error(g, node, buf_sprintf("defer expression outside function definition"));
- return g->builtin_types.entry_invalid;
- }
-
- if (!node->data.defer.expr) {
- add_node_error(g, node, buf_sprintf("defer expects an expression"));
- return g->builtin_types.entry_void;
- }
-
- node->data.defer.child_block = new_block_context(node, parent_context);
-
- TypeTableEntry *resolved_type = analyze_expression(g, import, parent_context, nullptr,
- node->data.defer.expr);
- validate_voided_expr(g, node->data.defer.expr, resolved_type);
-
- return g->builtin_types.entry_void;
-}
-
-static TypeTableEntry *analyze_string_literal_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
- TypeTableEntry *expected_type, AstNode *node)
-{
- if (node->data.string_literal.c) {
- return resolve_expr_const_val_as_c_string_lit(g, node, node->data.string_literal.buf);
- } else {
- return resolve_expr_const_val_as_string_lit(g, node, node->data.string_literal.buf);
- }
-}
-
-static TypeTableEntry *analyze_block_expr(CodeGen *g, ImportTableEntry *import, BlockContext *parent_context,
- TypeTableEntry *expected_type, AstNode *node)
-{
- BlockContext *child_context = new_block_context(node, parent_context);
- node->data.block.child_block = child_context;
- TypeTableEntry *return_type = g->builtin_types.entry_void;
-
- for (size_t i = 0; i < node->data.block.statements.length; i += 1) {
- AstNode *child = node->data.block.statements.at(i);
- if (child->type == NodeTypeLabel) {
- FnTableEntry *fn_table_entry = child_context->fn_entry;
- assert(fn_table_entry);
-
- LabelTableEntry *label = allocate<LabelTableEntry>(1);
- label->decl_node = child;
- label->entered_from_fallthrough = (return_type->id != TypeTableEntryIdUnreachable);
-
- child->block_context = child_context;
- child->data.label.label_entry = label;
- fn_table_entry->all_labels.append(label);
-
- child_context->label_table.put(child->data.label.name, label);
-
- return_type = g->builtin_types.entry_void;
- continue;
- }
- if (return_type->id == TypeTableEntryIdUnreachable) {
- if (is_node_void_expr(child)) {
- // {unreachable;void;void} is allowed.
- // ignore void statements once we enter unreachable land.
- analyze_expression(g, import, child_context, g->builtin_types.entry_void, child);
- continue;
- }
- add_node_error(g, first_executing_node(child), buf_sprintf("unreachable code"));
- break;
- }
- bool is_last = (i == node->data.block.statements.length - 1);
- TypeTableEntry *passed_expected_type = is_last ? expected_type : nullptr;
- return_type = analyze_expression(g, import, child_context, passed_expected_type, child);
- if (child->type == NodeTypeDefer && return_type->id != TypeTableEntryIdInvalid) {
- // defer starts a new block context
- child_context = child->data.defer.child_block;
- assert(child_context);
- }
- if (!is_last) {
- validate_voided_expr(g, child, return_type);
- }
- }
- node->data.block.nested_block = child_context;
-
- ConstExprValue *const_val = &node->data.block.resolved_expr.const_val;
- if (node->data.block.statements.length == 0) {
- const_val->ok = true;
- } else if (node->data.block.statements.length == 1) {
- AstNode *only_node = node->data.block.statements.at(0);
- ConstExprValue *other_const_val = &get_resolved_expr(only_node)->const_val;
- if (other_const_val->ok) {
- *const_val = *other_const_val;
- }
- }
-
- return return_type;
-}
-
-static TypeTableEntry *analyze_asm_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
- TypeTableEntry *expected_type, AstNode *node)
-{
- mark_impure_fn(g, context, node);
-
- node->data.asm_expr.return_count = 0;
- TypeTableEntry *return_type = g->builtin_types.entry_void;
- for (size_t i = 0; i < node->data.asm_expr.output_list.length; i += 1) {
- AsmOutput *asm_output = node->data.asm_expr.output_list.at(i);
- if (asm_output->return_type) {
- node->data.asm_expr.return_count += 1;
- return_type = analyze_type_expr(g, import, context, asm_output->return_type);
- if (node->data.asm_expr.return_count > 1) {
- add_node_error(g, node,
- buf_sprintf("inline assembly allows up to one output value"));
- break;
- }
- } else {
- Buf *variable_name = asm_output->variable_name;
- VariableTableEntry *var = find_variable(g, context, variable_name);
- if (var) {
- asm_output->variable = var;
- return var->type;
- } else {
- add_node_error(g, node,
- buf_sprintf("use of undeclared identifier '%s'", buf_ptr(variable_name)));
- return g->builtin_types.entry_invalid;
- }
- }
- }
- for (size_t i = 0; i < node->data.asm_expr.input_list.length; i += 1) {
- AsmInput *asm_input = node->data.asm_expr.input_list.at(i);
- analyze_expression(g, import, context, nullptr, asm_input->expr);
- }
-
- return return_type;
-}
-
-static TypeTableEntry *analyze_goto_pass1(CodeGen *g, ImportTableEntry *import, BlockContext *context,
- TypeTableEntry *expected_type, AstNode *node)
-{
- assert(node->type == NodeTypeGoto);
-
- FnTableEntry *fn_table_entry = context->fn_entry;
- assert(fn_table_entry);
-
- fn_table_entry->goto_list.append(node);
-
- return g->builtin_types.entry_unreachable;
-}
-
-static TypeTableEntry *analyze_expression_pointer_only(CodeGen *g, ImportTableEntry *import,
- BlockContext *context, TypeTableEntry *expected_type, AstNode *node, bool pointer_only)
-{
- assert(!expected_type || expected_type->id != TypeTableEntryIdInvalid);
- TypeTableEntry *return_type = nullptr;
- node->block_context = context;
- switch (node->type) {
- case NodeTypeBlock:
- return_type = analyze_block_expr(g, import, context, expected_type, node);
- break;
-
- case NodeTypeReturnExpr:
- return_type = analyze_return_expr(g, import, context, expected_type, node);
- break;
- case NodeTypeDefer:
- return_type = analyze_defer(g, import, context, expected_type, node);
- break;
- case NodeTypeVariableDeclaration:
- analyze_variable_declaration(g, import, context, expected_type, node);
- return_type = g->builtin_types.entry_void;
- break;
- case NodeTypeGoto:
- return_type = analyze_goto_pass1(g, import, context, expected_type, node);
- break;
- case NodeTypeBreak:
- return_type = analyze_break_expr(g, import, context, expected_type, node);
- break;
- case NodeTypeContinue:
- return_type = analyze_continue_expr(g, import, context, expected_type, node);
- break;
- case NodeTypeAsmExpr:
- return_type = analyze_asm_expr(g, import, context, expected_type, node);
- break;
- case NodeTypeBinOpExpr:
- return_type = analyze_bin_op_expr(g, import, context, expected_type, node);
- break;
- case NodeTypeUnwrapErrorExpr:
- return_type = analyze_unwrap_error_expr(g, import, context, expected_type, node);
- break;
- case NodeTypeFnCallExpr:
- return_type = analyze_fn_call_expr(g, import, context, expected_type, node);
- break;
-
- case NodeTypeArrayAccessExpr:
- // for reading array access; assignment handled elsewhere
- return_type = analyze_array_access_expr(g, import, context, node, LValPurposeAddressOf);
- break;
- case NodeTypeSliceExpr:
- return_type = analyze_slice_expr(g, import, context, node);
- break;
- case NodeTypeFieldAccessExpr:
- return_type = analyze_field_access_expr(g, import, context, expected_type, node);
- break;
- case NodeTypeContainerInitExpr:
- zig_panic("analyze container init moved to ir.cpp");
- break;
- case NodeTypeNumberLiteral:
- return_type = analyze_number_literal_expr(g, import, context, expected_type, node);
- break;
- case NodeTypeStringLiteral:
- return_type = analyze_string_literal_expr(g, import, context, expected_type, node);
- break;
- case NodeTypeCharLiteral:
- return_type = resolve_expr_const_val_as_unsigned_num_lit(g, node, expected_type,
- node->data.char_literal.value, false);
- break;
- case NodeTypeBoolLiteral:
- zig_panic("moved to ir.cpp");
- break;
- case NodeTypeNullLiteral:
- return_type = analyze_null_literal_expr(g, import, context, expected_type, node);
- break;
- case NodeTypeUndefinedLiteral:
- return_type = analyze_undefined_literal_expr(g, import, context, expected_type, node);
- break;
- case NodeTypeZeroesLiteral:
- return_type = analyze_zeroes_literal_expr(g, import, context, expected_type, node);
- break;
- case NodeTypeThisLiteral:
- zig_panic("moved to ir.cpp");
- break;
- case NodeTypeSymbol:
- return_type = analyze_symbol_expr(g, import, context, expected_type, node, pointer_only);
- break;
- case NodeTypePrefixOpExpr:
- zig_panic("moved to ir.cpp");
- break;
- case NodeTypeIfBoolExpr:
- return_type = analyze_if_bool_expr(g, import, context, expected_type, node);
- break;
- case NodeTypeIfVarExpr:
- return_type = analyze_if_var_expr(g, import, context, expected_type, node);
- break;
- case NodeTypeWhileExpr:
- return_type = analyze_while_expr(g, import, context, expected_type, node);
- break;
- case NodeTypeForExpr:
- zig_panic("moved to ir.cpp");
- break;
- case NodeTypeArrayType:
- return_type = analyze_array_type(g, import, context, expected_type, node);
- break;
- case NodeTypeFnProto:
- return_type = analyze_fn_proto_expr(g, import, context, expected_type, node);
- break;
- case NodeTypeErrorType:
- return_type = resolve_expr_const_val_as_type(g, node, g->builtin_types.entry_pure_error, false);
- break;
- case NodeTypeTypeLiteral:
- return_type = resolve_expr_const_val_as_type(g, node, g->builtin_types.entry_type, false);
- break;
- case NodeTypeSwitchExpr:
- return_type = analyze_switch_expr(g, import, context, expected_type, node);
- break;
- case NodeTypeVarLiteral:
- return_type = resolve_expr_const_val_as_type(g, node, g->builtin_types.entry_var, false);
- break;
- case NodeTypeSwitchProng:
- case NodeTypeSwitchRange:
- case NodeTypeFnDecl:
- case NodeTypeParamDecl:
- case NodeTypeRoot:
- case NodeTypeFnDef:
- case NodeTypeUse:
- case NodeTypeLabel:
- case NodeTypeContainerDecl:
- case NodeTypeStructField:
- case NodeTypeStructValueField:
- case NodeTypeErrorValueDecl:
- case NodeTypeTypeDecl:
- zig_unreachable();
- }
- assert(return_type);
- // resolve_type_compatibility might do implicit cast which means node is now a child
- // of the actual node that we want to return the type of.
- //AstNode **field = node->parent_field;
- TypeTableEntry *resolved_type = resolve_type_compatibility(g, import, context, node,
- expected_type, return_type);
-
- Expr *expr = get_resolved_expr(node);
- expr->type_entry = return_type;
-
- add_global_const_expr(g, node);
-
- return resolved_type;
-}
-
-// When you call analyze_expression, the node you pass might no longer be the child node
-// you thought it was due to implicit casting rewriting the AST.
-static TypeTableEntry *analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context,
- TypeTableEntry *expected_type, AstNode *node)
-{
- return analyze_expression_pointer_only(g, import, context, expected_type, node, false);
-}
-
-static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) {
- ImportTableEntry *import = fn_table_entry->import_entry;
- AstNode *node = fn_table_entry->fn_def_node;
- assert(node->type == NodeTypeFnDef);
-
- AstNode *fn_proto_node = node->data.fn_def.fn_proto;
- assert(fn_proto_node->type == NodeTypeFnProto);
-
- if (fn_proto_node->data.fn_proto.skip) {
- // we detected an error with this function definition which prevents us
- // from further analyzing it.
- fn_table_entry->anal_state = FnAnalStateSkipped;
- return;
- }
- fn_table_entry->anal_state = FnAnalStateProbing;
-
- BlockContext *context = node->data.fn_def.block_context;
-
- TypeTableEntry *fn_type = fn_table_entry->type_entry;
- AstNodeFnProto *fn_proto = &fn_proto_node->data.fn_proto;
- for (size_t i = 0; i < fn_proto->params.length; i += 1) {
- AstNode *param_decl_node = fn_proto->params.at(i);
- assert(param_decl_node->type == NodeTypeParamDecl);
-
- // define local variables for parameters
- AstNodeParamDecl *param_decl = ¶m_decl_node->data.param_decl;
- TypeTableEntry *type = unwrapped_node_type(param_decl->type);
-
- if (param_decl->is_noalias && !type_is_codegen_pointer(type)) {
- add_node_error(g, param_decl_node, buf_sprintf("noalias on non-pointer parameter"));
- }
+ if (param_decl->is_noalias && !type_is_codegen_pointer(type)) {
+ add_node_error(g, param_decl_node, buf_sprintf("noalias on non-pointer parameter"));
+ }
if (fn_type->data.fn.fn_type_id.is_extern && handle_is_ptr(type)) {
add_node_error(g, param_decl_node,
@@ -5340,162 +2591,6 @@ static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) {
fn_table_entry->anal_state = FnAnalStateComplete;
}
-static void add_top_level_decl(CodeGen *g, ImportTableEntry *import, BlockContext *block_context,
- AstNode *node, Buf *name)
-{
- assert(import);
-
- TopLevelDecl *tld = get_as_top_level_decl(node);
- tld->import = import;
- tld->name = name;
-
- 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;
-
- auto entry = block_context->decl_table.maybe_get(name);
- if (entry) {
- AstNode *other_decl_node = entry->value;
- ErrorMsg *msg = add_node_error(g, node, buf_sprintf("redefinition of '%s'", buf_ptr(name)));
- add_error_note(g, msg, other_decl_node, buf_sprintf("previous definition is here"));
- } else {
- block_context->decl_table.put(name, node);
- }
-}
-
-static void count_inline_and_var_args(AstNode *proto_node) {
- assert(proto_node->type == NodeTypeFnProto);
-
- size_t *inline_arg_count = &proto_node->data.fn_proto.inline_arg_count;
- size_t *inline_or_var_type_arg_count = &proto_node->data.fn_proto.inline_or_var_type_arg_count;
-
- *inline_arg_count = 0;
- *inline_or_var_type_arg_count = 0;
-
- // TODO run these nodes through the type analysis system rather than looking for
- // specialized ast nodes. this would get fooled by `{var}` instead of `var` which
- // is supposed to be equivalent
- for (size_t 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);
- if (param_node->data.param_decl.is_inline) {
- *inline_arg_count += 1;
- *inline_or_var_type_arg_count += 1;
- } else if (param_node->data.param_decl.type->type == NodeTypeVarLiteral) {
- *inline_or_var_type_arg_count += 1;
- }
- }
-}
-
-static void scan_decls(CodeGen *g, ImportTableEntry *import, BlockContext *context, AstNode *node) {
- switch (node->type) {
- case NodeTypeRoot:
- for (size_t i = 0; i < import->root->data.root.top_level_decls.length; i += 1) {
- AstNode *child = import->root->data.root.top_level_decls.at(i);
- scan_decls(g, import, context, child);
- }
- break;
- case NodeTypeContainerDecl:
- {
- Buf *name = node->data.struct_decl.name;
- add_top_level_decl(g, import, context, node, name);
- if (node->data.struct_decl.generic_params.length == 0) {
- scan_struct_decl(g, import, context, node);
- }
- }
- break;
- case NodeTypeFnDef:
- node->data.fn_def.fn_proto->data.fn_proto.fn_def_node = node;
- scan_decls(g, import, context, node->data.fn_def.fn_proto);
- break;
- case NodeTypeVariableDeclaration:
- {
- Buf *name = node->data.variable_declaration.symbol;
- add_top_level_decl(g, import, context, node, name);
- break;
- }
- case NodeTypeTypeDecl:
- {
- Buf *name = node->data.type_decl.symbol;
- add_top_level_decl(g, import, context, node, name);
- break;
- }
- case NodeTypeFnProto:
- {
- // if the name is missing, we immediately announce an error
- Buf *fn_name = node->data.fn_proto.name;
- if (buf_len(fn_name) == 0) {
- node->data.fn_proto.skip = true;
- add_node_error(g, node, buf_sprintf("missing function name"));
- break;
- }
- count_inline_and_var_args(node);
-
- add_top_level_decl(g, import, context, node, fn_name);
- break;
- }
- case NodeTypeUse:
- {
- TopLevelDecl *tld = get_as_top_level_decl(node);
- tld->import = import;
- node->block_context = context;
- g->use_queue.append(node);
- tld->import->use_decls.append(node);
- break;
- }
- case NodeTypeErrorValueDecl:
- // error value declarations do not depend on other top level decls
- preview_error_value_decl(g, node);
- break;
- case NodeTypeParamDecl:
- case NodeTypeFnDecl:
- case NodeTypeReturnExpr:
- case NodeTypeDefer:
- case NodeTypeBlock:
- case NodeTypeBinOpExpr:
- case NodeTypeUnwrapErrorExpr:
- case NodeTypeFnCallExpr:
- case NodeTypeArrayAccessExpr:
- case NodeTypeSliceExpr:
- case NodeTypeNumberLiteral:
- case NodeTypeStringLiteral:
- case NodeTypeCharLiteral:
- case NodeTypeBoolLiteral:
- case NodeTypeNullLiteral:
- case NodeTypeUndefinedLiteral:
- case NodeTypeZeroesLiteral:
- case NodeTypeThisLiteral:
- case NodeTypeSymbol:
- case NodeTypePrefixOpExpr:
- case NodeTypeIfBoolExpr:
- case NodeTypeIfVarExpr:
- case NodeTypeWhileExpr:
- case NodeTypeForExpr:
- case NodeTypeSwitchExpr:
- case NodeTypeSwitchProng:
- case NodeTypeSwitchRange:
- case NodeTypeLabel:
- case NodeTypeGoto:
- case NodeTypeBreak:
- case NodeTypeContinue:
- case NodeTypeAsmExpr:
- case NodeTypeFieldAccessExpr:
- case NodeTypeStructField:
- case NodeTypeContainerInitExpr:
- case NodeTypeStructValueField:
- case NodeTypeArrayType:
- case NodeTypeErrorType:
- case NodeTypeTypeLiteral:
- case NodeTypeVarLiteral:
- zig_unreachable();
- }
-}
-
static void add_symbols_from_import(CodeGen *g, AstNode *src_use_node, AstNode *dst_use_node) {
TopLevelDecl *tld = get_as_top_level_decl(dst_use_node);
AstNode *use_target_node = src_use_node->data.use.expr;
@@ -5565,11 +2660,11 @@ static void resolve_use_decl(CodeGen *g, AstNode *node) {
static void preview_use_decl(CodeGen *g, AstNode *node) {
assert(node->type == NodeTypeUse);
TopLevelDecl *tld = get_as_top_level_decl(node);
- TypeTableEntry *use_expr_type = analyze_expression(g, tld->import, tld->import->block_context,
- g->builtin_types.entry_namespace, node->data.use.expr);
- if (use_expr_type->id == TypeTableEntryIdInvalid) {
+
+ IrInstruction *result = analyze_const_value(g, tld->import->block_context, node->data.use.expr,
+ g->builtin_types.entry_namespace);
+ if (result->type_entry->id == TypeTableEntryIdInvalid)
tld->import->any_imports_failed = true;
- }
}
ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package,
src/analyze.hpp
@@ -45,10 +45,6 @@ ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package,
AstNode *first_executing_node(AstNode *node);
-TypeTableEntry *resolve_peer_type_compatibility(CodeGen *g, ImportTableEntry *import,
- BlockContext *block_context, AstNode *parent_source_node,
- AstNode **child_nodes, TypeTableEntry **child_types, size_t child_count);
-
// TODO move these over, these used to be static
bool types_match_const_cast_only(TypeTableEntry *expected_type, TypeTableEntry *actual_type);
src/ast_render.cpp
@@ -261,17 +261,6 @@ static void print_indent(AstRender *ar) {
}
}
-static bool is_node_void(AstNode *node) {
- if (node->type == NodeTypeSymbol) {
- if (node->data.symbol_expr.override_type_entry) {
- return node->data.symbol_expr.override_type_entry->id == TypeTableEntryIdVoid;
- } else if (buf_eql_str(node->data.symbol_expr.symbol, "void")) {
- return true;
- }
- }
- return false;
-}
-
static bool is_alpha_under(uint8_t c) {
return (c >= 'a' && c <= 'z') ||
(c >= 'A' && c <= 'Z') || c == '_';
@@ -406,10 +395,8 @@ static void render_node(AstRender *ar, AstNode *node) {
fprintf(ar->f, ")");
AstNode *return_type_node = node->data.fn_proto.return_type;
- if (!is_node_void(return_type_node)) {
- fprintf(ar->f, " -> ");
- render_node(ar, return_type_node);
- }
+ fprintf(ar->f, " -> ");
+ render_node(ar, return_type_node);
break;
}
case NodeTypeFnDef:
@@ -521,14 +508,7 @@ static void render_node(AstRender *ar, AstNode *node) {
break;
}
case NodeTypeSymbol:
- {
- TypeTableEntry *override_type = node->data.symbol_expr.override_type_entry;
- if (override_type) {
- fprintf(ar->f, "%s", buf_ptr(&override_type->name));
- } else {
- print_symbol(ar, node->data.symbol_expr.symbol);
- }
- }
+ print_symbol(ar, node->data.symbol_expr.symbol);
break;
case NodeTypePrefixOpExpr:
{
@@ -623,10 +603,8 @@ static void render_node(AstRender *ar, AstNode *node) {
assert(field_node->type == NodeTypeStructField);
print_indent(ar);
print_symbol(ar, field_node->data.struct_field.name);
- if (!is_node_void(field_node->data.struct_field.type)) {
- fprintf(ar->f, ": ");
- render_node(ar, field_node->data.struct_field.type);
- }
+ fprintf(ar->f, ": ");
+ render_node(ar, field_node->data.struct_field.type);
fprintf(ar->f, ",\n");
}
src/codegen.cpp
@@ -2965,6 +2965,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
case IrInstructionIdToPtrType:
case IrInstructionIdPtrTypeChild:
case IrInstructionIdFieldPtr:
+ case IrInstructionIdSetFnTest:
zig_unreachable();
case IrInstructionIdReturn:
return ir_render_return(g, executable, (IrInstructionReturn *)instruction);
@@ -2996,7 +2997,6 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_struct_field_ptr(g, executable, (IrInstructionStructFieldPtr *)instruction);
case IrInstructionIdSwitchBr:
case IrInstructionIdPhi:
- case IrInstructionIdBuiltinCall:
case IrInstructionIdContainerInitList:
case IrInstructionIdContainerInitFields:
case IrInstructionIdReadField:
@@ -5303,8 +5303,6 @@ static void get_c_type(CodeGen *g, TypeTableEntry *type_entry, Buf *out_buf) {
}
static void get_c_type_node(CodeGen *g, AstNode *type_node, Buf *out_buf) {
- assert(type_node->type != NodeTypeSymbol || !type_node->data.symbol_expr.override_type_entry);
-
Expr *expr = get_resolved_expr(type_node);
assert(expr->type_entry);
assert(expr->type_entry->id == TypeTableEntryIdMetaType);
src/ir.cpp
@@ -149,10 +149,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionCall *) {
return IrInstructionIdCall;
}
-static constexpr IrInstructionId ir_instruction_id(IrInstructionBuiltinCall *) {
- return IrInstructionIdBuiltinCall;
-}
-
static constexpr IrInstructionId ir_instruction_id(IrInstructionConst *) {
return IrInstructionIdConst;
}
@@ -189,6 +185,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionPtrTypeChild *)
return IrInstructionIdPtrTypeChild;
}
+static constexpr IrInstructionId ir_instruction_id(IrInstructionSetFnTest *) {
+ return IrInstructionIdSetFnTest;
+}
+
template<typename T>
static T *ir_create_instruction(IrExecutable *exec, AstNode *source_node) {
T *special_instruction = allocate<T>(1);
@@ -353,7 +353,7 @@ static IrInstruction *ir_build_const_scope(IrBuilder *irb, AstNode *source_node,
static IrInstruction *ir_build_const_bool(IrBuilder *irb, AstNode *source_node, bool value) {
IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, source_node);
- const_instruction->base.type_entry = irb->codegen->builtin_types.entry_block;
+ const_instruction->base.type_entry = irb->codegen->builtin_types.entry_bool;
const_instruction->base.static_value.ok = true;
const_instruction->base.static_value.data.x_bool = value;
return &const_instruction->base;
@@ -505,20 +505,6 @@ static IrInstruction *ir_build_call_from(IrBuilder *irb, IrInstruction *old_inst
return new_instruction;
}
-static IrInstruction *ir_build_builtin_call(IrBuilder *irb, AstNode *source_node,
- BuiltinFnEntry *fn, IrInstruction **args)
-{
- IrInstructionBuiltinCall *call_instruction = ir_build_instruction<IrInstructionBuiltinCall>(irb, source_node);
- call_instruction->fn = fn;
- call_instruction->args = args;
-
- for (size_t i = 0; i < fn->param_count; i += 1) {
- ir_ref_instruction(args[i]);
- }
-
- return &call_instruction->base;
-}
-
static IrInstruction *ir_build_phi(IrBuilder *irb, AstNode *source_node,
size_t incoming_count, IrBasicBlock **incoming_blocks, IrInstruction **incoming_values)
{
@@ -717,6 +703,19 @@ static IrInstruction *ir_build_ptr_type_child(IrBuilder *irb, AstNode *source_no
return &instruction->base;
}
+static IrInstruction *ir_build_set_fn_test(IrBuilder *irb, AstNode *source_node, IrInstruction *fn_value,
+ IrInstruction *is_test)
+{
+ IrInstructionSetFnTest *instruction = ir_build_instruction<IrInstructionSetFnTest>(irb, source_node);
+ instruction->fn_value = fn_value;
+ instruction->is_test = is_test;
+
+ ir_ref_instruction(fn_value);
+ ir_ref_instruction(is_test);
+
+ return &instruction->base;
+}
+
//static size_t get_conditional_defer_count(BlockContext *inner_block, BlockContext *outer_block) {
// size_t result = 0;
// while (inner_block != outer_block) {
@@ -1066,10 +1065,6 @@ static IrInstruction *ir_gen_decl_ref(IrBuilder *irb, AstNode *source_node, AstN
static IrInstruction *ir_gen_symbol(IrBuilder *irb, AstNode *node, LValPurpose lval) {
assert(node->type == NodeTypeSymbol);
- if (node->data.symbol_expr.override_type_entry) {
- zig_panic("TODO have parseh directly generate IR");
- }
-
Buf *variable_name = node->data.symbol_expr.symbol;
auto primitive_table_entry = irb->codegen->primitive_type_table.maybe_get(variable_name);
@@ -1163,26 +1158,71 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, AstNode *node) {
builtin_fn->ref_count += 1;
- if (builtin_fn->id == BuiltinFnIdUnreachable) {
- return ir_build_unreachable(irb, node);
- } else if (builtin_fn->id == BuiltinFnIdTypeof) {
- AstNode *arg_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg = ir_gen_node(irb, arg_node, node->block_context);
- if (arg == irb->codegen->invalid_instruction)
- return arg;
- return ir_build_typeof(irb, node, arg);
- }
+ switch (builtin_fn->id) {
+ case BuiltinFnIdInvalid:
+ zig_unreachable();
+ case BuiltinFnIdUnreachable:
+ return ir_build_unreachable(irb, node);
+ case BuiltinFnIdTypeof:
+ {
+ AstNode *arg_node = node->data.fn_call_expr.params.at(0);
+ IrInstruction *arg = ir_gen_node(irb, arg_node, node->block_context);
+ if (arg == irb->codegen->invalid_instruction)
+ return arg;
+ return ir_build_typeof(irb, node, arg);
+ }
+ case BuiltinFnIdSetFnTest:
+ {
+ AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, node->block_context);
+ if (arg0_value == irb->codegen->invalid_instruction)
+ return arg0_value;
- IrInstruction **args = allocate<IrInstruction *>(actual_param_count);
- for (size_t i = 0; i < actual_param_count; i += 1) {
- AstNode *arg_node = node->data.fn_call_expr.params.at(i);
- IrInstruction *arg = ir_gen_node(irb, arg_node, node->block_context);
- if (arg == irb->codegen->invalid_instruction)
- return arg;
- args[i] = arg;
- }
+ AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, node->block_context);
+ if (arg1_value == irb->codegen->invalid_instruction)
+ return arg1_value;
- return ir_build_builtin_call(irb, node, builtin_fn, args);
+ return ir_build_set_fn_test(irb, node, arg0_value, arg1_value);
+ }
+ case BuiltinFnIdMemcpy:
+ case BuiltinFnIdMemset:
+ case BuiltinFnIdSizeof:
+ case BuiltinFnIdAlignof:
+ case BuiltinFnIdMaxValue:
+ case BuiltinFnIdMinValue:
+ case BuiltinFnIdMemberCount:
+ case BuiltinFnIdAddWithOverflow:
+ case BuiltinFnIdSubWithOverflow:
+ case BuiltinFnIdMulWithOverflow:
+ case BuiltinFnIdShlWithOverflow:
+ case BuiltinFnIdCInclude:
+ case BuiltinFnIdCDefine:
+ case BuiltinFnIdCUndef:
+ case BuiltinFnIdCompileVar:
+ case BuiltinFnIdCompileErr:
+ case BuiltinFnIdConstEval:
+ case BuiltinFnIdCtz:
+ case BuiltinFnIdClz:
+ case BuiltinFnIdImport:
+ case BuiltinFnIdCImport:
+ case BuiltinFnIdErrName:
+ case BuiltinFnIdBreakpoint:
+ case BuiltinFnIdReturnAddress:
+ case BuiltinFnIdFrameAddress:
+ case BuiltinFnIdEmbedFile:
+ case BuiltinFnIdCmpExchange:
+ case BuiltinFnIdFence:
+ case BuiltinFnIdDivExact:
+ case BuiltinFnIdTruncate:
+ case BuiltinFnIdIntType:
+ case BuiltinFnIdSetFnVisible:
+ case BuiltinFnIdSetFnStaticEval:
+ case BuiltinFnIdSetFnNoInline:
+ case BuiltinFnIdSetDebugSafety:
+ zig_panic("TODO IR gen more builtin functions");
+ }
+ zig_unreachable();
}
static IrInstruction *ir_gen_fn_call(IrBuilder *irb, AstNode *node) {
@@ -2044,6 +2084,53 @@ static TypeTableEntry *ir_resolve_type(IrAnalyze *ira, IrInstruction *type_value
return const_val->data.x_type;
}
+static bool ir_resolve_bool(IrAnalyze *ira, IrInstruction *bool_value, bool *out) {
+ if (bool_value == ira->codegen->invalid_instruction)
+ return false;
+
+ if (bool_value->type_entry->id == TypeTableEntryIdInvalid)
+ return false;
+
+ if (bool_value->type_entry->id != TypeTableEntryIdBool) {
+ add_node_error(ira->codegen, bool_value->source_node,
+ buf_sprintf("expected type 'bool', found '%s'", buf_ptr(&bool_value->type_entry->name)));
+ return false;
+ }
+
+ ConstExprValue *const_val = &bool_value->static_value;
+ if (!const_val->ok) {
+ add_node_error(ira->codegen, bool_value->source_node,
+ buf_sprintf("unable to evaluate constant expression"));
+ return false;
+ }
+
+ *out = const_val->data.x_bool;
+ return true;
+}
+
+static FnTableEntry *ir_resolve_fn(IrAnalyze *ira, IrInstruction *fn_value) {
+ if (fn_value == ira->codegen->invalid_instruction)
+ return nullptr;
+
+ if (fn_value->type_entry->id == TypeTableEntryIdInvalid)
+ return nullptr;
+
+ if (fn_value->type_entry->id != TypeTableEntryIdFn) {
+ add_node_error(ira->codegen, fn_value->source_node,
+ buf_sprintf("expected function type, found '%s'", buf_ptr(&fn_value->type_entry->name)));
+ return nullptr;
+ }
+
+ ConstExprValue *const_val = &fn_value->static_value;
+ if (!const_val->ok) {
+ add_node_error(ira->codegen, fn_value->source_node,
+ buf_sprintf("unable to evaluate constant expression"));
+ return nullptr;
+ }
+
+ return const_val->data.x_fn;
+}
+
static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_instr,
IrInstruction *dest_type, IrInstruction *value)
{
@@ -2837,11 +2924,18 @@ static TypeTableEntry *ir_analyze_instruction_call(IrAnalyze *ira, IrInstruction
} else if (fn_ref->type_entry->id == TypeTableEntryIdFn) {
// TODO fully port over the fn call analyze code to IR
FnTableEntry *fn_table_entry = fn_ref->static_value.data.x_fn;
+ TypeTableEntry *fn_type = fn_table_entry->type_entry;
+
+ IrInstruction **casted_args = allocate<IrInstruction *>(call_instruction->arg_count);
+ for (size_t i = 0; i < call_instruction->arg_count; i += 1) {
+ TypeTableEntry *param_type = fn_type->data.fn.fn_type_id.param_info[i].type;
+ IrInstruction *old_arg = call_instruction->args[i]->other;
+ casted_args[i] = ir_get_casted_value(ira, old_arg, param_type);
+ }
ir_build_call_from(&ira->new_irb, &call_instruction->base,
- call_instruction->fn, call_instruction->arg_count, call_instruction->args);
+ call_instruction->fn, call_instruction->arg_count, casted_args);
- TypeTableEntry *fn_type = fn_table_entry->type_entry;
TypeTableEntry *return_type = fn_type->data.fn.fn_type_id.return_type;
return return_type;
} else {
@@ -3075,1121 +3169,8 @@ static TypeTableEntry *ir_analyze_instruction_un_op(IrAnalyze *ira, IrInstructio
zig_unreachable();
}
-//static TypeTableEntry *analyze_min_max_value(CodeGen *g, ImportTableEntry *import, BlockContext *context,
-// AstNode *node, const char *err_format, bool is_max)
-//{
-// assert(node->type == NodeTypeFnCallExpr);
-// assert(node->data.fn_call_expr.params.length == 1);
-//
-// AstNode *type_node = node->data.fn_call_expr.params.at(0);
-// TypeTableEntry *type_entry = analyze_type_expr(g, import, context, type_node);
-//
-// if (type_entry->id == TypeTableEntryIdInvalid) {
-// return g->builtin_types.entry_invalid;
-// } else if (type_entry->id == TypeTableEntryIdInt) {
-// eval_min_max_value(g, type_entry, &get_resolved_expr(node)->const_val, is_max);
-// return g->builtin_types.entry_num_lit_int;
-// } else if (type_entry->id == TypeTableEntryIdFloat) {
-// eval_min_max_value(g, type_entry, &get_resolved_expr(node)->const_val, is_max);
-// return g->builtin_types.entry_num_lit_float;
-// } else if (type_entry->id == TypeTableEntryIdBool) {
-// eval_min_max_value(g, type_entry, &get_resolved_expr(node)->const_val, is_max);
-// return type_entry;
-// } else {
-// add_node_error(g, node,
-// buf_sprintf(err_format, buf_ptr(&type_entry->name)));
-// return g->builtin_types.entry_invalid;
-// }
-//}
-
-//static TypeTableEntry *analyze_import(CodeGen *g, ImportTableEntry *import, BlockContext *context,
-// AstNode *node)
-//{
-// assert(node->type == NodeTypeFnCallExpr);
-//
-// if (context->fn_entry) {
-// add_node_error(g, node, buf_sprintf("@import invalid inside function bodies"));
-// return g->builtin_types.entry_invalid;
-// }
-//
-// AstNode *first_param_node = node->data.fn_call_expr.params.at(0);
-// Buf *import_target_str = resolve_const_expr_str(g, import, context, first_param_node->parent_field);
-// if (!import_target_str) {
-// return g->builtin_types.entry_invalid;
-// }
-//
-// Buf *import_target_path;
-// Buf *search_dir;
-// assert(import->package);
-// PackageTableEntry *target_package;
-// auto package_entry = import->package->package_table.maybe_get(import_target_str);
-// if (package_entry) {
-// target_package = package_entry->value;
-// import_target_path = &target_package->root_src_path;
-// search_dir = &target_package->root_src_dir;
-// } else {
-// // try it as a filename
-// target_package = import->package;
-// import_target_path = import_target_str;
-// search_dir = &import->package->root_src_dir;
-// }
-//
-// Buf full_path = BUF_INIT;
-// os_path_join(search_dir, import_target_path, &full_path);
-//
-// Buf *import_code = buf_alloc();
-// Buf *abs_full_path = buf_alloc();
-// int err;
-// if ((err = os_path_real(&full_path, abs_full_path))) {
-// if (err == ErrorFileNotFound) {
-// add_node_error(g, node,
-// buf_sprintf("unable to find '%s'", buf_ptr(import_target_path)));
-// return g->builtin_types.entry_invalid;
-// } else {
-// g->error_during_imports = true;
-// add_node_error(g, node,
-// buf_sprintf("unable to open '%s': %s", buf_ptr(&full_path), err_str(err)));
-// return g->builtin_types.entry_invalid;
-// }
-// }
-//
-// auto import_entry = g->import_table.maybe_get(abs_full_path);
-// if (import_entry) {
-// return resolve_expr_const_val_as_import(g, node, import_entry->value);
-// }
-//
-// if ((err = os_fetch_file_path(abs_full_path, import_code))) {
-// if (err == ErrorFileNotFound) {
-// add_node_error(g, node,
-// buf_sprintf("unable to find '%s'", buf_ptr(import_target_path)));
-// return g->builtin_types.entry_invalid;
-// } else {
-// add_node_error(g, node,
-// buf_sprintf("unable to open '%s': %s", buf_ptr(&full_path), err_str(err)));
-// return g->builtin_types.entry_invalid;
-// }
-// }
-// ImportTableEntry *target_import = add_source_file(g, target_package,
-// abs_full_path, search_dir, import_target_path, import_code);
-//
-// scan_decls(g, target_import, target_import->block_context, target_import->root);
-//
-// return resolve_expr_const_val_as_import(g, node, target_import);
-//}
-//
-//static TypeTableEntry *analyze_c_import(CodeGen *g, ImportTableEntry *parent_import,
-// BlockContext *parent_context, AstNode *node)
-//{
-// assert(node->type == NodeTypeFnCallExpr);
-//
-// if (parent_context->fn_entry) {
-// add_node_error(g, node, buf_sprintf("@c_import invalid inside function bodies"));
-// return g->builtin_types.entry_invalid;
-// }
-//
-// AstNode *block_node = node->data.fn_call_expr.params.at(0);
-//
-// BlockContext *child_context = new_block_context(node, parent_context);
-// child_context->c_import_buf = buf_alloc();
-//
-// TypeTableEntry *resolved_type = analyze_expression(g, parent_import, child_context,
-// g->builtin_types.entry_void, block_node);
-//
-// if (resolved_type->id == TypeTableEntryIdInvalid) {
-// return resolved_type;
-// }
-//
-// find_libc_include_path(g);
-//
-// ImportTableEntry *child_import = allocate<ImportTableEntry>(1);
-// child_import->c_import_node = node;
-//
-// ZigList<ErrorMsg *> errors = {0};
-//
-// int err;
-// if ((err = parse_h_buf(child_import, &errors, child_context->c_import_buf, g, node))) {
-// zig_panic("unable to parse h file: %s\n", err_str(err));
-// }
-//
-// if (errors.length > 0) {
-// ErrorMsg *parent_err_msg = add_node_error(g, node, buf_sprintf("C import failed"));
-// for (size_t i = 0; i < errors.length; i += 1) {
-// ErrorMsg *err_msg = errors.at(i);
-// err_msg_add_note(parent_err_msg, err_msg);
-// }
-//
-// return g->builtin_types.entry_invalid;
-// }
-//
-// if (g->verbose) {
-// fprintf(stderr, "\nc_import:\n");
-// fprintf(stderr, "-----------\n");
-// ast_render(stderr, child_import->root, 4);
-// }
-//
-// child_import->di_file = parent_import->di_file;
-// child_import->block_context = new_block_context(child_import->root, nullptr);
-//
-// scan_decls(g, child_import, child_import->block_context, child_import->root);
-// return resolve_expr_const_val_as_import(g, node, child_import);
-//}
-//
-//static TypeTableEntry *analyze_err_name(CodeGen *g, ImportTableEntry *import,
-// BlockContext *context, AstNode *node)
-//{
-// assert(node->type == NodeTypeFnCallExpr);
-//
-// AstNode *err_value = node->data.fn_call_expr.params.at(0);
-// TypeTableEntry *resolved_type = analyze_expression(g, import, context,
-// g->builtin_types.entry_pure_error, err_value);
-//
-// if (resolved_type->id == TypeTableEntryIdInvalid) {
-// return resolved_type;
-// }
-//
-// g->generate_error_name_table = true;
-//
-// TypeTableEntry *str_type = get_slice_type(g, g->builtin_types.entry_u8, true);
-// return str_type;
-//}
-//
-//static TypeTableEntry *analyze_embed_file(CodeGen *g, ImportTableEntry *import,
-// BlockContext *context, AstNode *node)
-//{
-// assert(node->type == NodeTypeFnCallExpr);
-//
-// AstNode **first_param_node = &node->data.fn_call_expr.params.at(0);
-// Buf *rel_file_path = resolve_const_expr_str(g, import, context, first_param_node);
-// if (!rel_file_path) {
-// return g->builtin_types.entry_invalid;
-// }
-//
-// // figure out absolute path to resource
-// Buf source_dir_path = BUF_INIT;
-// os_path_dirname(import->path, &source_dir_path);
-//
-// Buf file_path = BUF_INIT;
-// os_path_resolve(&source_dir_path, rel_file_path, &file_path);
-//
-// // load from file system into const expr
-// Buf file_contents = BUF_INIT;
-// int err;
-// if ((err = os_fetch_file_path(&file_path, &file_contents))) {
-// if (err == ErrorFileNotFound) {
-// add_node_error(g, node,
-// buf_sprintf("unable to find '%s'", buf_ptr(&file_path)));
-// return g->builtin_types.entry_invalid;
-// } else {
-// add_node_error(g, node,
-// buf_sprintf("unable to open '%s': %s", buf_ptr(&file_path), err_str(err)));
-// return g->builtin_types.entry_invalid;
-// }
-// }
-//
-// // TODO add dependency on the file we embedded so that we know if it changes
-// // we'll have to invalidate the cache
-//
-// return resolve_expr_const_val_as_string_lit(g, node, &file_contents);
-//}
-//
-//static TypeTableEntry *analyze_cmpxchg(CodeGen *g, ImportTableEntry *import,
-// BlockContext *context, AstNode *node)
-//{
-// assert(node->type == NodeTypeFnCallExpr);
-//
-// AstNode **ptr_arg = &node->data.fn_call_expr.params.at(0);
-// AstNode **cmp_arg = &node->data.fn_call_expr.params.at(1);
-// AstNode **new_arg = &node->data.fn_call_expr.params.at(2);
-// AstNode **success_order_arg = &node->data.fn_call_expr.params.at(3);
-// AstNode **failure_order_arg = &node->data.fn_call_expr.params.at(4);
-//
-// TypeTableEntry *ptr_type = analyze_expression(g, import, context, nullptr, *ptr_arg);
-// if (ptr_type->id == TypeTableEntryIdInvalid) {
-// return g->builtin_types.entry_invalid;
-// } else if (ptr_type->id != TypeTableEntryIdPointer) {
-// add_node_error(g, *ptr_arg,
-// buf_sprintf("expected pointer argument, got '%s'", buf_ptr(&ptr_type->name)));
-// return g->builtin_types.entry_invalid;
-// }
-//
-// TypeTableEntry *child_type = ptr_type->data.pointer.child_type;
-// TypeTableEntry *cmp_type = analyze_expression(g, import, context, child_type, *cmp_arg);
-// TypeTableEntry *new_type = analyze_expression(g, import, context, child_type, *new_arg);
-//
-// TypeTableEntry *success_order_type = analyze_expression(g, import, context,
-// g->builtin_types.entry_atomic_order_enum, *success_order_arg);
-// TypeTableEntry *failure_order_type = analyze_expression(g, import, context,
-// g->builtin_types.entry_atomic_order_enum, *failure_order_arg);
-//
-// if (cmp_type->id == TypeTableEntryIdInvalid ||
-// new_type->id == TypeTableEntryIdInvalid ||
-// success_order_type->id == TypeTableEntryIdInvalid ||
-// failure_order_type->id == TypeTableEntryIdInvalid)
-// {
-// return g->builtin_types.entry_invalid;
-// }
-//
-// ConstExprValue *success_order_val = &get_resolved_expr(*success_order_arg)->const_val;
-// ConstExprValue *failure_order_val = &get_resolved_expr(*failure_order_arg)->const_val;
-// if (!success_order_val->ok) {
-// add_node_error(g, *success_order_arg, buf_sprintf("unable to evaluate constant expression"));
-// return g->builtin_types.entry_invalid;
-// } else if (!failure_order_val->ok) {
-// add_node_error(g, *failure_order_arg, buf_sprintf("unable to evaluate constant expression"));
-// return g->builtin_types.entry_invalid;
-// }
-//
-// if (success_order_val->data.x_enum.tag < AtomicOrderMonotonic) {
-// add_node_error(g, *success_order_arg,
-// buf_sprintf("success atomic ordering must be Monotonic or stricter"));
-// return g->builtin_types.entry_invalid;
-// }
-// if (failure_order_val->data.x_enum.tag < AtomicOrderMonotonic) {
-// add_node_error(g, *failure_order_arg,
-// buf_sprintf("failure atomic ordering must be Monotonic or stricter"));
-// return g->builtin_types.entry_invalid;
-// }
-// if (failure_order_val->data.x_enum.tag > success_order_val->data.x_enum.tag) {
-// add_node_error(g, *failure_order_arg,
-// buf_sprintf("failure atomic ordering must be no stricter than success"));
-// return g->builtin_types.entry_invalid;
-// }
-// if (failure_order_val->data.x_enum.tag == AtomicOrderRelease ||
-// failure_order_val->data.x_enum.tag == AtomicOrderAcqRel)
-// {
-// add_node_error(g, *failure_order_arg,
-// buf_sprintf("failure atomic ordering must not be Release or AcqRel"));
-// return g->builtin_types.entry_invalid;
-// }
-//
-// return g->builtin_types.entry_bool;
-//}
-//
-//static TypeTableEntry *analyze_fence(CodeGen *g, ImportTableEntry *import,
-// BlockContext *context, AstNode *node)
-//{
-// assert(node->type == NodeTypeFnCallExpr);
-//
-// AstNode **atomic_order_arg = &node->data.fn_call_expr.params.at(0);
-// TypeTableEntry *atomic_order_type = analyze_expression(g, import, context,
-// g->builtin_types.entry_atomic_order_enum, *atomic_order_arg);
-//
-// if (atomic_order_type->id == TypeTableEntryIdInvalid) {
-// return g->builtin_types.entry_invalid;
-// }
-//
-// ConstExprValue *atomic_order_val = &get_resolved_expr(*atomic_order_arg)->const_val;
-//
-// if (!atomic_order_val->ok) {
-// add_node_error(g, *atomic_order_arg, buf_sprintf("unable to evaluate constant expression"));
-// return g->builtin_types.entry_invalid;
-// }
-//
-// return g->builtin_types.entry_void;
-//}
-//
-//static TypeTableEntry *analyze_div_exact(CodeGen *g, ImportTableEntry *import,
-// BlockContext *context, AstNode *node)
-//{
-// assert(node->type == NodeTypeFnCallExpr);
-//
-// AstNode **op1 = &node->data.fn_call_expr.params.at(0);
-// AstNode **op2 = &node->data.fn_call_expr.params.at(1);
-//
-// TypeTableEntry *op1_type = analyze_expression(g, import, context, nullptr, *op1);
-// TypeTableEntry *op2_type = analyze_expression(g, import, context, nullptr, *op2);
-//
-// AstNode *op_nodes[] = {*op1, *op2};
-// TypeTableEntry *op_types[] = {op1_type, op2_type};
-// TypeTableEntry *result_type = resolve_peer_type_compatibility(g, import, context, node,
-// op_nodes, op_types, 2);
-//
-// if (result_type->id == TypeTableEntryIdInvalid) {
-// return g->builtin_types.entry_invalid;
-// } else if (result_type->id == TypeTableEntryIdInt) {
-// return result_type;
-// } else if (result_type->id == TypeTableEntryIdNumLitInt) {
-// // check for division by zero
-// // check for non exact division
-// zig_panic("TODO");
-// } else {
-// add_node_error(g, node,
-// buf_sprintf("expected integer type, got '%s'", buf_ptr(&result_type->name)));
-// return g->builtin_types.entry_invalid;
-// }
-//}
-//
-//static TypeTableEntry *analyze_truncate(CodeGen *g, ImportTableEntry *import,
-// BlockContext *context, AstNode *node)
-//{
-// assert(node->type == NodeTypeFnCallExpr);
-//
-// AstNode **op1 = &node->data.fn_call_expr.params.at(0);
-// AstNode **op2 = &node->data.fn_call_expr.params.at(1);
-//
-// TypeTableEntry *dest_type = analyze_type_expr(g, import, context, *op1);
-// TypeTableEntry *src_type = analyze_expression(g, import, context, nullptr, *op2);
-//
-// if (dest_type->id == TypeTableEntryIdInvalid || src_type->id == TypeTableEntryIdInvalid) {
-// return g->builtin_types.entry_invalid;
-// } else if (dest_type->id != TypeTableEntryIdInt) {
-// add_node_error(g, *op1,
-// buf_sprintf("expected integer type, got '%s'", buf_ptr(&dest_type->name)));
-// return g->builtin_types.entry_invalid;
-// } else if (src_type->id != TypeTableEntryIdInt) {
-// add_node_error(g, *op2,
-// buf_sprintf("expected integer type, got '%s'", buf_ptr(&src_type->name)));
-// return g->builtin_types.entry_invalid;
-// } else if (src_type->data.integral.is_signed != dest_type->data.integral.is_signed) {
-// const char *sign_str = dest_type->data.integral.is_signed ? "signed" : "unsigned";
-// add_node_error(g, *op2,
-// buf_sprintf("expected %s integer type, got '%s'", sign_str, buf_ptr(&src_type->name)));
-// return g->builtin_types.entry_invalid;
-// } else if (src_type->data.integral.bit_count <= dest_type->data.integral.bit_count) {
-// add_node_error(g, *op2,
-// buf_sprintf("type '%s' has same or fewer bits than destination type '%s'",
-// buf_ptr(&src_type->name), buf_ptr(&dest_type->name)));
-// return g->builtin_types.entry_invalid;
-// }
-//
-// // TODO const expr eval
-//
-// return dest_type;
-//}
-//
-//static TypeTableEntry *analyze_compile_err(CodeGen *g, ImportTableEntry *import,
-// BlockContext *context, AstNode *node)
-//{
-// AstNode *first_param_node = node->data.fn_call_expr.params.at(0);
-// Buf *err_msg = resolve_const_expr_str(g, import, context, first_param_node->parent_field);
-// if (!err_msg) {
-// return g->builtin_types.entry_invalid;
-// }
-//
-// add_node_error(g, node, err_msg);
-//
-// return g->builtin_types.entry_invalid;
-//}
-//
-//static TypeTableEntry *analyze_int_type(CodeGen *g, ImportTableEntry *import,
-// BlockContext *context, AstNode *node)
-//{
-// AstNode **is_signed_node = &node->data.fn_call_expr.params.at(0);
-// AstNode **bit_count_node = &node->data.fn_call_expr.params.at(1);
-//
-// TypeTableEntry *bool_type = g->builtin_types.entry_bool;
-// TypeTableEntry *usize_type = g->builtin_types.entry_usize;
-// TypeTableEntry *is_signed_type = analyze_expression(g, import, context, bool_type, *is_signed_node);
-// TypeTableEntry *bit_count_type = analyze_expression(g, import, context, usize_type, *bit_count_node);
-//
-// if (is_signed_type->id == TypeTableEntryIdInvalid ||
-// bit_count_type->id == TypeTableEntryIdInvalid)
-// {
-// return g->builtin_types.entry_invalid;
-// }
-//
-// ConstExprValue *is_signed_val = &get_resolved_expr(*is_signed_node)->const_val;
-// ConstExprValue *bit_count_val = &get_resolved_expr(*bit_count_node)->const_val;
-//
-// AstNode *bad_node = nullptr;
-// if (!is_signed_val->ok) {
-// bad_node = *is_signed_node;
-// } else if (!bit_count_val->ok) {
-// bad_node = *bit_count_node;
-// }
-// if (bad_node) {
-// add_node_error(g, bad_node, buf_sprintf("unable to evaluate constant expression"));
-// return g->builtin_types.entry_invalid;
-// }
-//
-// bool depends_on_compile_var = is_signed_val->depends_on_compile_var || bit_count_val->depends_on_compile_var;
-//
-// TypeTableEntry *int_type = get_int_type(g, is_signed_val->data.x_bool,
-// bit_count_val->data.x_bignum.data.x_uint);
-// return resolve_expr_const_val_as_type(g, node, int_type, depends_on_compile_var);
-//
-//}
-//
-//static TypeTableEntry *analyze_set_fn_test(CodeGen *g, ImportTableEntry *import,
-// BlockContext *context, AstNode *node)
-//{
-// AstNode **fn_node = &node->data.fn_call_expr.params.at(0);
-// AstNode **value_node = &node->data.fn_call_expr.params.at(1);
-//
-// FnTableEntry *fn_entry = resolve_const_expr_fn(g, import, context, fn_node);
-// if (!fn_entry) {
-// return g->builtin_types.entry_invalid;
-// }
-//
-// bool ok = resolve_const_expr_bool(g, import, context, value_node, &fn_entry->is_test);
-// if (!ok) {
-// return g->builtin_types.entry_invalid;
-// }
-//
-// if (fn_entry->fn_test_set_node) {
-// ErrorMsg *msg = add_node_error(g, node, buf_sprintf("function test attribute set twice"));
-// add_error_note(g, msg, fn_entry->fn_test_set_node, buf_sprintf("first set here"));
-// return g->builtin_types.entry_invalid;
-// }
-// fn_entry->fn_test_set_node = node;
-//
-// g->test_fn_count += 1;
-// return g->builtin_types.entry_void;
-//}
-//
-//static TypeTableEntry *analyze_set_fn_no_inline(CodeGen *g, ImportTableEntry *import,
-// BlockContext *context, AstNode *node)
-//{
-// AstNode **fn_node = &node->data.fn_call_expr.params.at(0);
-// AstNode **value_node = &node->data.fn_call_expr.params.at(1);
-//
-// FnTableEntry *fn_entry = resolve_const_expr_fn(g, import, context, fn_node);
-// if (!fn_entry) {
-// return g->builtin_types.entry_invalid;
-// }
-//
-// bool is_noinline;
-// bool ok = resolve_const_expr_bool(g, import, context, value_node, &is_noinline);
-// if (!ok) {
-// return g->builtin_types.entry_invalid;
-// }
-//
-// if (fn_entry->fn_no_inline_set_node) {
-// ErrorMsg *msg = add_node_error(g, node, buf_sprintf("function no inline attribute set twice"));
-// add_error_note(g, msg, fn_entry->fn_no_inline_set_node, buf_sprintf("first set here"));
-// return g->builtin_types.entry_invalid;
-// }
-// fn_entry->fn_no_inline_set_node = node;
-//
-// if (fn_entry->fn_inline == FnInlineAlways) {
-// add_node_error(g, node, buf_sprintf("function is both inline and noinline"));
-// fn_entry->proto_node->data.fn_proto.skip = true;
-// return g->builtin_types.entry_invalid;
-// } else if (is_noinline) {
-// fn_entry->fn_inline = FnInlineNever;
-// }
-//
-// return g->builtin_types.entry_void;
-//}
-//
-//static TypeTableEntry *analyze_set_fn_static_eval(CodeGen *g, ImportTableEntry *import,
-// BlockContext *context, AstNode *node)
-//{
-// AstNode **fn_node = &node->data.fn_call_expr.params.at(0);
-// AstNode **value_node = &node->data.fn_call_expr.params.at(1);
-//
-// FnTableEntry *fn_entry = resolve_const_expr_fn(g, import, context, fn_node);
-// if (!fn_entry) {
-// return g->builtin_types.entry_invalid;
-// }
-//
-// bool want_static_eval;
-// bool ok = resolve_const_expr_bool(g, import, context, value_node, &want_static_eval);
-// if (!ok) {
-// return g->builtin_types.entry_invalid;
-// }
-//
-// if (fn_entry->fn_static_eval_set_node) {
-// ErrorMsg *msg = add_node_error(g, node, buf_sprintf("function static eval attribute set twice"));
-// add_error_note(g, msg, fn_entry->fn_static_eval_set_node, buf_sprintf("first set here"));
-// return g->builtin_types.entry_invalid;
-// }
-// fn_entry->fn_static_eval_set_node = node;
-//
-// if (want_static_eval && !context->fn_entry->is_pure) {
-// add_node_error(g, node, buf_sprintf("attribute appears too late within function"));
-// return g->builtin_types.entry_invalid;
-// }
-//
-// if (want_static_eval) {
-// fn_entry->want_pure = WantPureTrue;
-// fn_entry->want_pure_attr_node = node;
-// } else {
-// fn_entry->want_pure = WantPureFalse;
-// fn_entry->is_pure = false;
-// }
-//
-// return g->builtin_types.entry_void;
-//}
-//
-//static TypeTableEntry *analyze_set_fn_visible(CodeGen *g, ImportTableEntry *import,
-// BlockContext *context, AstNode *node)
-//{
-// AstNode **fn_node = &node->data.fn_call_expr.params.at(0);
-// AstNode **value_node = &node->data.fn_call_expr.params.at(1);
-//
-// FnTableEntry *fn_entry = resolve_const_expr_fn(g, import, context, fn_node);
-// if (!fn_entry) {
-// return g->builtin_types.entry_invalid;
-// }
-//
-// bool want_export;
-// bool ok = resolve_const_expr_bool(g, import, context, value_node, &want_export);
-// if (!ok) {
-// return g->builtin_types.entry_invalid;
-// }
-//
-// if (fn_entry->fn_export_set_node) {
-// ErrorMsg *msg = add_node_error(g, node, buf_sprintf("function visibility set twice"));
-// add_error_note(g, msg, fn_entry->fn_export_set_node, buf_sprintf("first set here"));
-// return g->builtin_types.entry_invalid;
-// }
-// fn_entry->fn_export_set_node = node;
-//
-// AstNodeFnProto *fn_proto = &fn_entry->proto_node->data.fn_proto;
-// if (fn_proto->top_level_decl.visib_mod != VisibModExport) {
-// ErrorMsg *msg = add_node_error(g, node,
-// buf_sprintf("function must be marked export to set function visibility"));
-// add_error_note(g, msg, fn_entry->proto_node, buf_sprintf("function declared here"));
-// return g->builtin_types.entry_void;
-// }
-// if (!want_export) {
-// fn_proto->top_level_decl.visib_mod = VisibModPub;
-// }
-//
-// return g->builtin_types.entry_void;
-//}
-//
-//static TypeTableEntry *analyze_set_debug_safety(CodeGen *g, ImportTableEntry *import,
-// BlockContext *parent_context, AstNode *node)
-//{
-// AstNode **target_node = &node->data.fn_call_expr.params.at(0);
-// AstNode **value_node = &node->data.fn_call_expr.params.at(1);
-//
-// TypeTableEntry *target_type = analyze_expression(g, import, parent_context, nullptr, *target_node);
-// BlockContext *target_context;
-// ConstExprValue *const_val = &get_resolved_expr(*target_node)->const_val;
-// if (target_type->id == TypeTableEntryIdInvalid) {
-// return g->builtin_types.entry_invalid;
-// }
-// if (!const_val->ok) {
-// add_node_error(g, *target_node, buf_sprintf("unable to evaluate constant expression"));
-// return g->builtin_types.entry_invalid;
-// }
-// if (target_type->id == TypeTableEntryIdBlock) {
-// target_context = const_val->data.x_block;
-// } else if (target_type->id == TypeTableEntryIdFn) {
-// target_context = const_val->data.x_fn->fn_def_node->data.fn_def.block_context;
-// } else if (target_type->id == TypeTableEntryIdMetaType) {
-// TypeTableEntry *type_arg = const_val->data.x_type;
-// if (type_arg->id == TypeTableEntryIdStruct) {
-// target_context = type_arg->data.structure.block_context;
-// } else if (type_arg->id == TypeTableEntryIdEnum) {
-// target_context = type_arg->data.enumeration.block_context;
-// } else if (type_arg->id == TypeTableEntryIdUnion) {
-// target_context = type_arg->data.unionation.block_context;
-// } else {
-// add_node_error(g, *target_node,
-// buf_sprintf("expected scope reference, got type '%s'", buf_ptr(&type_arg->name)));
-// return g->builtin_types.entry_invalid;
-// }
-// } else {
-// add_node_error(g, *target_node,
-// buf_sprintf("expected scope reference, got type '%s'", buf_ptr(&target_type->name)));
-// return g->builtin_types.entry_invalid;
-// }
-//
-// bool want_debug_safety;
-// bool ok = resolve_const_expr_bool(g, import, parent_context, value_node, &want_debug_safety);
-// if (!ok) {
-// return g->builtin_types.entry_invalid;
-// }
-//
-// if (target_context->safety_set_node) {
-// ErrorMsg *msg = add_node_error(g, node, buf_sprintf("debug safety for scope set twice"));
-// add_error_note(g, msg, target_context->safety_set_node, buf_sprintf("first set here"));
-// return g->builtin_types.entry_invalid;
-// }
-// target_context->safety_set_node = node;
-//
-// target_context->safety_off = !want_debug_safety;
-//
-// return g->builtin_types.entry_void;
-//}
-
-
-//static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
-// TypeTableEntry *expected_type, AstNode *node)
-//{
-//
-// switch (builtin_fn->id) {
-// case BuiltinFnIdInvalid:
-// zig_unreachable();
-// case BuiltinFnIdAddWithOverflow:
-// case BuiltinFnIdSubWithOverflow:
-// case BuiltinFnIdMulWithOverflow:
-// case BuiltinFnIdShlWithOverflow:
-// {
-// AstNode *type_node = node->data.fn_call_expr.params.at(0);
-// TypeTableEntry *int_type = analyze_type_expr(g, import, context, type_node);
-// if (int_type->id == TypeTableEntryIdInvalid) {
-// return g->builtin_types.entry_bool;
-// } else if (int_type->id == TypeTableEntryIdInt) {
-// AstNode *op1_node = node->data.fn_call_expr.params.at(1);
-// AstNode *op2_node = node->data.fn_call_expr.params.at(2);
-// AstNode *result_node = node->data.fn_call_expr.params.at(3);
-//
-// analyze_expression(g, import, context, int_type, op1_node);
-// analyze_expression(g, import, context, int_type, op2_node);
-// analyze_expression(g, import, context, get_pointer_to_type(g, int_type, false),
-// result_node);
-// } else {
-// add_node_error(g, type_node,
-// buf_sprintf("expected integer type, got '%s'", buf_ptr(&int_type->name)));
-// }
-//
-// // TODO constant expression evaluation
-//
-// return g->builtin_types.entry_bool;
-// }
-// case BuiltinFnIdMemcpy:
-// {
-// AstNode *dest_node = node->data.fn_call_expr.params.at(0);
-// AstNode *src_node = node->data.fn_call_expr.params.at(1);
-// AstNode *len_node = node->data.fn_call_expr.params.at(2);
-// TypeTableEntry *dest_type = analyze_expression(g, import, context, nullptr, dest_node);
-// TypeTableEntry *src_type = analyze_expression(g, import, context, nullptr, src_node);
-// analyze_expression(g, import, context, builtin_fn->param_types[2], len_node);
-//
-// if (dest_type->id != TypeTableEntryIdInvalid &&
-// dest_type->id != TypeTableEntryIdPointer)
-// {
-// add_node_error(g, dest_node,
-// buf_sprintf("expected pointer argument, got '%s'", buf_ptr(&dest_type->name)));
-// }
-//
-// if (src_type->id != TypeTableEntryIdInvalid &&
-// src_type->id != TypeTableEntryIdPointer)
-// {
-// add_node_error(g, src_node,
-// buf_sprintf("expected pointer argument, got '%s'", buf_ptr(&src_type->name)));
-// }
-//
-// if (dest_type->id == TypeTableEntryIdPointer &&
-// src_type->id == TypeTableEntryIdPointer)
-// {
-// uint64_t dest_align = get_memcpy_align(g, dest_type->data.pointer.child_type);
-// uint64_t src_align = get_memcpy_align(g, src_type->data.pointer.child_type);
-// if (dest_align != src_align) {
-// add_node_error(g, dest_node, buf_sprintf(
-// "misaligned memcpy, '%s' has alignment '%" PRIu64 ", '%s' has alignment %" PRIu64,
-// buf_ptr(&dest_type->name), dest_align,
-// buf_ptr(&src_type->name), src_align));
-// }
-// }
-//
-// return builtin_fn->return_type;
-// }
-// case BuiltinFnIdMemset:
-// {
-// AstNode *dest_node = node->data.fn_call_expr.params.at(0);
-// AstNode *char_node = node->data.fn_call_expr.params.at(1);
-// AstNode *len_node = node->data.fn_call_expr.params.at(2);
-// TypeTableEntry *dest_type = analyze_expression(g, import, context, nullptr, dest_node);
-// analyze_expression(g, import, context, builtin_fn->param_types[1], char_node);
-// analyze_expression(g, import, context, builtin_fn->param_types[2], len_node);
-//
-// if (dest_type->id != TypeTableEntryIdInvalid &&
-// dest_type->id != TypeTableEntryIdPointer)
-// {
-// add_node_error(g, dest_node,
-// buf_sprintf("expected pointer argument, got '%s'", buf_ptr(&dest_type->name)));
-// }
-//
-// return builtin_fn->return_type;
-// }
-// case BuiltinFnIdSizeof:
-// {
-// AstNode *type_node = node->data.fn_call_expr.params.at(0);
-// TypeTableEntry *type_entry = analyze_type_expr(g, import, context, type_node);
-// if (type_entry->id == TypeTableEntryIdInvalid) {
-// return g->builtin_types.entry_invalid;
-// } else if (type_entry->id == TypeTableEntryIdUnreachable) {
-// add_node_error(g, first_executing_node(type_node),
-// buf_sprintf("no size available for type '%s'", buf_ptr(&type_entry->name)));
-// return g->builtin_types.entry_invalid;
-// } else {
-// uint64_t size_in_bytes = type_size(g, type_entry);
-// bool depends_on_compile_var = (type_entry == g->builtin_types.entry_usize ||
-// type_entry == g->builtin_types.entry_isize);
-// return resolve_expr_const_val_as_unsigned_num_lit(g, node, expected_type,
-// size_in_bytes, depends_on_compile_var);
-// }
-// }
-// case BuiltinFnIdAlignof:
-// {
-// AstNode *type_node = node->data.fn_call_expr.params.at(0);
-// TypeTableEntry *type_entry = analyze_type_expr(g, import, context, type_node);
-// if (type_entry->id == TypeTableEntryIdInvalid) {
-// return g->builtin_types.entry_invalid;
-// } else if (type_entry->id == TypeTableEntryIdUnreachable) {
-// add_node_error(g, first_executing_node(type_node),
-// buf_sprintf("no align available for type '%s'", buf_ptr(&type_entry->name)));
-// return g->builtin_types.entry_invalid;
-// } else {
-// uint64_t align_in_bytes = LLVMABISizeOfType(g->target_data_ref, type_entry->type_ref);
-// return resolve_expr_const_val_as_unsigned_num_lit(g, node, expected_type,
-// align_in_bytes, false);
-// }
-// }
-// case BuiltinFnIdMaxValue:
-// return analyze_min_max_value(g, import, context, node,
-// "no max value available for type '%s'", true);
-// case BuiltinFnIdMinValue:
-// return analyze_min_max_value(g, import, context, node,
-// "no min value available for type '%s'", false);
-// case BuiltinFnIdMemberCount:
-// {
-// AstNode *type_node = node->data.fn_call_expr.params.at(0);
-// TypeTableEntry *type_entry = analyze_type_expr(g, import, context, type_node);
-//
-// if (type_entry->id == TypeTableEntryIdInvalid) {
-// return type_entry;
-// } else if (type_entry->id == TypeTableEntryIdEnum) {
-// uint64_t value_count = type_entry->data.enumeration.src_field_count;
-// return resolve_expr_const_val_as_unsigned_num_lit(g, node, expected_type,
-// value_count, false);
-// } else {
-// add_node_error(g, node,
-// buf_sprintf("no value count available for type '%s'", buf_ptr(&type_entry->name)));
-// return g->builtin_types.entry_invalid;
-// }
-// }
-// case BuiltinFnIdCInclude:
-// {
-// if (!context->c_import_buf) {
-// add_node_error(g, node, buf_sprintf("@c_include valid only in c_import blocks"));
-// return g->builtin_types.entry_invalid;
-// }
-//
-// AstNode **str_node = node->data.fn_call_expr.params.at(0)->parent_field;
-// TypeTableEntry *str_type = get_slice_type(g, g->builtin_types.entry_u8, true);
-// TypeTableEntry *resolved_type = analyze_expression(g, import, context, str_type, *str_node);
-//
-// if (resolved_type->id == TypeTableEntryIdInvalid) {
-// return resolved_type;
-// }
-//
-// ConstExprValue *const_str_val = &get_resolved_expr(*str_node)->const_val;
-//
-// if (!const_str_val->ok) {
-// add_node_error(g, *str_node, buf_sprintf("@c_include requires constant expression"));
-// return g->builtin_types.entry_void;
-// }
-//
-// buf_appendf(context->c_import_buf, "#include <");
-// ConstExprValue *ptr_field = const_str_val->data.x_struct.fields[0];
-// uint64_t len = ptr_field->data.x_ptr.len;
-// for (uint64_t i = 0; i < len; i += 1) {
-// ConstExprValue *char_val = ptr_field->data.x_ptr.ptr[i];
-// uint64_t big_c = char_val->data.x_bignum.data.x_uint;
-// assert(big_c <= UINT8_MAX);
-// uint8_t c = big_c;
-// buf_append_char(context->c_import_buf, c);
-// }
-// buf_appendf(context->c_import_buf, ">\n");
-//
-// return g->builtin_types.entry_void;
-// }
-// case BuiltinFnIdCDefine:
-// zig_panic("TODO");
-// case BuiltinFnIdCUndef:
-// zig_panic("TODO");
-//
-// case BuiltinFnIdCompileVar:
-// {
-// AstNode **str_node = node->data.fn_call_expr.params.at(0)->parent_field;
-//
-// Buf *var_name = resolve_const_expr_str(g, import, context, str_node);
-// if (!var_name) {
-// return g->builtin_types.entry_invalid;
-// }
-//
-// ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
-// const_val->ok = true;
-// const_val->depends_on_compile_var = true;
-//
-// if (buf_eql_str(var_name, "is_big_endian")) {
-// return resolve_expr_const_val_as_bool(g, node, g->is_big_endian, true);
-// } else if (buf_eql_str(var_name, "is_release")) {
-// return resolve_expr_const_val_as_bool(g, node, g->is_release_build, true);
-// } else if (buf_eql_str(var_name, "is_test")) {
-// return resolve_expr_const_val_as_bool(g, node, g->is_test_build, true);
-// } else if (buf_eql_str(var_name, "os")) {
-// const_val->data.x_enum.tag = g->target_os_index;
-// return g->builtin_types.entry_os_enum;
-// } else if (buf_eql_str(var_name, "arch")) {
-// const_val->data.x_enum.tag = g->target_arch_index;
-// return g->builtin_types.entry_arch_enum;
-// } else if (buf_eql_str(var_name, "environ")) {
-// const_val->data.x_enum.tag = g->target_environ_index;
-// return g->builtin_types.entry_environ_enum;
-// } else if (buf_eql_str(var_name, "object_format")) {
-// const_val->data.x_enum.tag = g->target_oformat_index;
-// return g->builtin_types.entry_oformat_enum;
-// } else {
-// add_node_error(g, *str_node,
-// buf_sprintf("unrecognized compile variable: '%s'", buf_ptr(var_name)));
-// return g->builtin_types.entry_invalid;
-// }
-// }
-// case BuiltinFnIdConstEval:
-// {
-// AstNode **expr_node = node->data.fn_call_expr.params.at(0)->parent_field;
-// TypeTableEntry *resolved_type = analyze_expression(g, import, context, expected_type, *expr_node);
-// if (resolved_type->id == TypeTableEntryIdInvalid) {
-// return resolved_type;
-// }
-//
-// ConstExprValue *const_expr_val = &get_resolved_expr(*expr_node)->const_val;
-//
-// if (!const_expr_val->ok) {
-// add_node_error(g, *expr_node, buf_sprintf("unable to evaluate constant expression"));
-// return g->builtin_types.entry_invalid;
-// }
-//
-// ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
-// *const_val = *const_expr_val;
-//
-// return resolved_type;
-// }
-// case BuiltinFnIdCtz:
-// case BuiltinFnIdClz:
-// {
-// AstNode *type_node = node->data.fn_call_expr.params.at(0);
-// TypeTableEntry *int_type = analyze_type_expr(g, import, context, type_node);
-// if (int_type->id == TypeTableEntryIdInvalid) {
-// return int_type;
-// } else if (int_type->id == TypeTableEntryIdInt) {
-// AstNode **expr_node = node->data.fn_call_expr.params.at(1)->parent_field;
-// TypeTableEntry *resolved_type = analyze_expression(g, import, context, int_type, *expr_node);
-// if (resolved_type->id == TypeTableEntryIdInvalid) {
-// return resolved_type;
-// }
-//
-// // TODO const expr eval
-//
-// return resolved_type;
-// } else {
-// add_node_error(g, type_node,
-// buf_sprintf("expected integer type, got '%s'", buf_ptr(&int_type->name)));
-// return g->builtin_types.entry_invalid;
-// }
-// }
-// case BuiltinFnIdImport:
-// return analyze_import(g, import, context, node);
-// case BuiltinFnIdCImport:
-// return analyze_c_import(g, import, context, node);
-// case BuiltinFnIdErrName:
-// return analyze_err_name(g, import, context, node);
-// case BuiltinFnIdBreakpoint:
-// mark_impure_fn(g, context, node);
-// return g->builtin_types.entry_void;
-// case BuiltinFnIdReturnAddress:
-// case BuiltinFnIdFrameAddress:
-// mark_impure_fn(g, context, node);
-// return builtin_fn->return_type;
-// case BuiltinFnIdEmbedFile:
-// return analyze_embed_file(g, import, context, node);
-// case BuiltinFnIdCmpExchange:
-// return analyze_cmpxchg(g, import, context, node);
-// case BuiltinFnIdFence:
-// return analyze_fence(g, import, context, node);
-// case BuiltinFnIdDivExact:
-// return analyze_div_exact(g, import, context, node);
-// case BuiltinFnIdTruncate:
-// return analyze_truncate(g, import, context, node);
-// case BuiltinFnIdCompileErr:
-// return analyze_compile_err(g, import, context, node);
-// case BuiltinFnIdIntType:
-// return analyze_int_type(g, import, context, node);
-// case BuiltinFnIdSetFnTest:
-// return analyze_set_fn_test(g, import, context, node);
-// case BuiltinFnIdSetFnNoInline:
-// return analyze_set_fn_no_inline(g, import, context, node);
-// case BuiltinFnIdSetFnStaticEval:
-// return analyze_set_fn_static_eval(g, import, context, node);
-// case BuiltinFnIdSetFnVisible:
-// return analyze_set_fn_visible(g, import, context, node);
-// case BuiltinFnIdSetDebugSafety:
-// return analyze_set_debug_safety(g, import, context, node);
-// }
-// zig_unreachable();
-//}
-
-//static TypeTableEntry *analyze_container_init_expr(CodeGen *g, ImportTableEntry *import,
-// BlockContext *context, AstNode *node)
-//{
-// assert(node->type == NodeTypeContainerInitExpr);
-//
-// AstNodeContainerInitExpr *container_init_expr = &node->data.container_init_expr;
-//
-// ContainerInitKind kind = container_init_expr->kind;
-//
-// if (container_init_expr->type->type == NodeTypeFieldAccessExpr) {
-// container_init_expr->type->data.field_access_expr.container_init_expr_node = node;
-// }
-//
-// TypeTableEntry *container_meta_type = analyze_expression(g, import, context, nullptr,
-// container_init_expr->type);
-//
-// if (container_meta_type->id == TypeTableEntryIdInvalid) {
-// return g->builtin_types.entry_invalid;
-// }
-//
-// if (node->data.container_init_expr.enum_type) {
-// get_resolved_expr(node)->const_val = get_resolved_expr(container_init_expr->type)->const_val;
-// return node->data.container_init_expr.enum_type;
-// }
-//
-// TypeTableEntry *container_type = resolve_type(g, container_init_expr->type);
-//
-// if (container_type->id == TypeTableEntryIdInvalid) {
-// return container_type;
-// } else if (container_type->id == TypeTableEntryIdStruct &&
-// !container_type->data.structure.is_slice &&
-// (kind == ContainerInitKindStruct || (kind == ContainerInitKindArray &&
-// container_init_expr->entries.length == 0)))
-// {
-// StructValExprCodeGen *codegen = &container_init_expr->resolved_struct_val_expr;
-// codegen->type_entry = container_type;
-// codegen->source_node = node;
-//
-//
-// size_t expr_field_count = container_init_expr->entries.length;
-// size_t actual_field_count = container_type->data.structure.src_field_count;
-//
-// AstNode *non_const_expr_culprit = nullptr;
-//
-// size_t *field_use_counts = allocate<size_t>(actual_field_count);
-// ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
-// const_val->ok = true;
-// const_val->data.x_struct.fields = allocate<ConstExprValue*>(actual_field_count);
-// for (size_t i = 0; i < expr_field_count; i += 1) {
-// AstNode *val_field_node = container_init_expr->entries.at(i);
-// assert(val_field_node->type == NodeTypeStructValueField);
-//
-// val_field_node->block_context = context;
-//
-// TypeStructField *type_field = find_struct_type_field(container_type,
-// val_field_node->data.struct_val_field.name);
-//
-// if (!type_field) {
-// add_node_error(g, val_field_node,
-// buf_sprintf("no member named '%s' in '%s'",
-// buf_ptr(val_field_node->data.struct_val_field.name), buf_ptr(&container_type->name)));
-// continue;
-// }
-//
-// if (type_field->type_entry->id == TypeTableEntryIdInvalid) {
-// return g->builtin_types.entry_invalid;
-// }
-//
-// size_t field_index = type_field->src_index;
-// field_use_counts[field_index] += 1;
-// if (field_use_counts[field_index] > 1) {
-// add_node_error(g, val_field_node, buf_sprintf("duplicate field"));
-// continue;
-// }
-//
-// val_field_node->data.struct_val_field.type_struct_field = type_field;
-//
-// analyze_expression(g, import, context, type_field->type_entry,
-// val_field_node->data.struct_val_field.expr);
-//
-// if (const_val->ok) {
-// ConstExprValue *field_val =
-// &get_resolved_expr(val_field_node->data.struct_val_field.expr)->const_val;
-// if (field_val->ok) {
-// const_val->data.x_struct.fields[field_index] = field_val;
-// const_val->depends_on_compile_var = const_val->depends_on_compile_var || field_val->depends_on_compile_var;
-// } else {
-// const_val->ok = false;
-// non_const_expr_culprit = val_field_node->data.struct_val_field.expr;
-// }
-// }
-// }
-// if (!const_val->ok) {
-// assert(non_const_expr_culprit);
-// if (context->fn_entry) {
-// context->fn_entry->struct_val_expr_alloca_list.append(codegen);
-// } else {
-// add_node_error(g, non_const_expr_culprit, buf_sprintf("unable to evaluate constant expression"));
-// }
-// }
-//
-// for (size_t i = 0; i < actual_field_count; i += 1) {
-// if (field_use_counts[i] == 0) {
-// add_node_error(g, node,
-// buf_sprintf("missing field: '%s'", buf_ptr(container_type->data.structure.fields[i].name)));
-// }
-// }
-// return container_type;
-// } else if (container_type->id == TypeTableEntryIdStruct &&
-// container_type->data.structure.is_slice &&
-// kind == ContainerInitKindArray)
-// {
-// size_t elem_count = container_init_expr->entries.length;
-//
-// TypeTableEntry *pointer_type = container_type->data.structure.fields[0].type_entry;
-// assert(pointer_type->id == TypeTableEntryIdPointer);
-// TypeTableEntry *child_type = pointer_type->data.pointer.child_type;
-//
-// ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
-// const_val->ok = true;
-// const_val->data.x_array.fields = allocate<ConstExprValue*>(elem_count);
-//
-// for (size_t i = 0; i < elem_count; i += 1) {
-// AstNode **elem_node = &container_init_expr->entries.at(i);
-// analyze_expression(g, import, context, child_type, *elem_node);
-//
-// if (const_val->ok) {
-// ConstExprValue *elem_const_val = &get_resolved_expr(*elem_node)->const_val;
-// if (elem_const_val->ok) {
-// const_val->data.x_array.fields[i] = elem_const_val;
-// const_val->depends_on_compile_var = const_val->depends_on_compile_var ||
-// elem_const_val->depends_on_compile_var;
-// } else {
-// const_val->ok = false;
-// }
-// }
-// }
-//
-// TypeTableEntry *fixed_size_array_type = get_array_type(g, child_type, elem_count);
-//
-// StructValExprCodeGen *codegen = &container_init_expr->resolved_struct_val_expr;
-// codegen->type_entry = fixed_size_array_type;
-// codegen->source_node = node;
-// if (!const_val->ok) {
-// if (!context->fn_entry) {
-// add_node_error(g, node,
-// buf_sprintf("unable to evaluate constant expression"));
-// } else {
-// context->fn_entry->struct_val_expr_alloca_list.append(codegen);
-// }
-// }
-//
-// return fixed_size_array_type;
-// } else if (container_type->id == TypeTableEntryIdArray) {
-// zig_panic("TODO array container init");
-// return container_type;
-// } else if (container_type->id == TypeTableEntryIdVoid) {
-// if (container_init_expr->entries.length != 0) {
-// add_node_error(g, node, buf_sprintf("void expression expects no arguments"));
-// return g->builtin_types.entry_invalid;
-// } else {
-// return resolve_expr_const_val_as_void(g, node);
-// }
-// } else {
-// add_node_error(g, node,
-// buf_sprintf("type '%s' does not support %s initialization syntax",
-// buf_ptr(&container_type->name), err_container_init_syntax_name(kind)));
-// return g->builtin_types.entry_invalid;
-// }
-//}
-
-static TypeTableEntry *ir_analyze_instruction_br(IrAnalyze *ira, IrInstructionBr *br_instruction) {
- IrBasicBlock *old_dest_block = br_instruction->dest_block;
+static TypeTableEntry *ir_analyze_instruction_br(IrAnalyze *ira, IrInstructionBr *br_instruction) {
+ IrBasicBlock *old_dest_block = br_instruction->dest_block;
// TODO detect backward jumps
@@ -4235,55 +3216,6 @@ static TypeTableEntry *ir_analyze_instruction_cond_br(IrAnalyze *ira, IrInstruct
return ira->codegen->builtin_types.entry_unreachable;
}
-static TypeTableEntry *ir_analyze_instruction_builtin_call(IrAnalyze *ira,
- IrInstructionBuiltinCall *builtin_call_instruction)
-{
- switch (builtin_call_instruction->fn->id) {
- case BuiltinFnIdInvalid:
- case BuiltinFnIdUnreachable:
- case BuiltinFnIdTypeof:
- zig_unreachable();
- case BuiltinFnIdMemcpy:
- case BuiltinFnIdMemset:
- case BuiltinFnIdSizeof:
- case BuiltinFnIdAlignof:
- case BuiltinFnIdMaxValue:
- case BuiltinFnIdMinValue:
- case BuiltinFnIdMemberCount:
- case BuiltinFnIdAddWithOverflow:
- case BuiltinFnIdSubWithOverflow:
- case BuiltinFnIdMulWithOverflow:
- case BuiltinFnIdShlWithOverflow:
- case BuiltinFnIdCInclude:
- case BuiltinFnIdCDefine:
- case BuiltinFnIdCUndef:
- case BuiltinFnIdCompileVar:
- case BuiltinFnIdCompileErr:
- case BuiltinFnIdConstEval:
- case BuiltinFnIdCtz:
- case BuiltinFnIdClz:
- case BuiltinFnIdImport:
- case BuiltinFnIdCImport:
- case BuiltinFnIdErrName:
- case BuiltinFnIdBreakpoint:
- case BuiltinFnIdReturnAddress:
- case BuiltinFnIdFrameAddress:
- case BuiltinFnIdEmbedFile:
- case BuiltinFnIdCmpExchange:
- case BuiltinFnIdFence:
- case BuiltinFnIdDivExact:
- case BuiltinFnIdTruncate:
- case BuiltinFnIdIntType:
- case BuiltinFnIdSetFnTest:
- case BuiltinFnIdSetFnVisible:
- case BuiltinFnIdSetFnStaticEval:
- case BuiltinFnIdSetFnNoInline:
- case BuiltinFnIdSetDebugSafety:
- zig_panic("TODO analyze more builtin functions");
- }
- zig_unreachable();
-}
-
static TypeTableEntry *ir_analyze_instruction_unreachable(IrAnalyze *ira,
IrInstructionUnreachable *unreachable_instruction)
{
@@ -4731,6 +3663,34 @@ static TypeTableEntry *ir_analyze_instruction_ptr_type_child(IrAnalyze *ira,
return ira->codegen->builtin_types.entry_type;
}
+static TypeTableEntry *ir_analyze_instruction_set_fn_test(IrAnalyze *ira,
+ IrInstructionSetFnTest *set_fn_test_instruction)
+{
+ IrInstruction *fn_value = set_fn_test_instruction->fn_value->other;
+ IrInstruction *is_test_value = set_fn_test_instruction->is_test->other;
+
+ FnTableEntry *fn_entry = ir_resolve_fn(ira, fn_value);
+ if (!fn_entry)
+ return ira->codegen->builtin_types.entry_invalid;
+
+ if (!ir_resolve_bool(ira, is_test_value, &fn_entry->is_test))
+ return ira->codegen->builtin_types.entry_invalid;
+
+ AstNode *source_node = set_fn_test_instruction->base.source_node;
+ if (fn_entry->fn_test_set_node) {
+ ErrorMsg *msg = add_node_error(ira->codegen, source_node,
+ buf_sprintf("function test attribute set twice"));
+ add_error_note(ira->codegen, msg, fn_entry->fn_test_set_node, buf_sprintf("first set here"));
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+ fn_entry->fn_test_set_node = source_node;
+
+ ira->codegen->test_fn_count += 1;
+
+ ir_build_const_from(ira, &set_fn_test_instruction->base, false);
+ return ira->codegen->builtin_types.entry_void;
+}
+
static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
switch (instruction->id) {
case IrInstructionIdInvalid:
@@ -4763,8 +3723,6 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
return ir_analyze_instruction_br(ira, (IrInstructionBr *)instruction);
case IrInstructionIdCondBr:
return ir_analyze_instruction_cond_br(ira, (IrInstructionCondBr *)instruction);
- case IrInstructionIdBuiltinCall:
- return ir_analyze_instruction_builtin_call(ira, (IrInstructionBuiltinCall *)instruction);
case IrInstructionIdUnreachable:
return ir_analyze_instruction_unreachable(ira, (IrInstructionUnreachable *)instruction);
case IrInstructionIdPhi:
@@ -4775,175 +3733,3488 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
return ir_analyze_instruction_to_ptr_type(ira, (IrInstructionToPtrType *)instruction);
case IrInstructionIdPtrTypeChild:
return ir_analyze_instruction_ptr_type_child(ira, (IrInstructionPtrTypeChild *)instruction);
+ case IrInstructionIdSetFnTest:
+ return ir_analyze_instruction_set_fn_test(ira, (IrInstructionSetFnTest *)instruction);
+ case IrInstructionIdSwitchBr:
+ case IrInstructionIdCast:
+ case IrInstructionIdContainerInitList:
+ case IrInstructionIdContainerInitFields:
+ case IrInstructionIdStructFieldPtr:
+ zig_panic("TODO analyze more instructions");
+ }
+ zig_unreachable();
+}
+
+static TypeTableEntry *ir_analyze_instruction(IrAnalyze *ira, IrInstruction *instruction) {
+ TypeTableEntry *instruction_type = ir_analyze_instruction_nocast(ira, instruction);
+ instruction->type_entry = instruction_type;
+ if (instruction->other) {
+ instruction->other->type_entry = instruction_type;
+ } else {
+ assert(instruction_type->id == TypeTableEntryIdInvalid ||
+ instruction_type->id == TypeTableEntryIdUnreachable);
+ instruction->other = instruction;
+ }
+ return instruction_type;
+}
+
+// This function attempts to evaluate IR code while doing type checking and other analysis.
+// It emits a new IrExecutable which is partially evaluated IR code.
+TypeTableEntry *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_exec,
+ TypeTableEntry *expected_type, AstNode *expected_type_source_node)
+{
+ IrAnalyze ir_analyze_data = {};
+ IrAnalyze *ira = &ir_analyze_data;
+ ira->codegen = codegen;
+ ira->explicit_return_type = expected_type;
+
+ ira->old_irb.codegen = codegen;
+ ira->old_irb.exec = old_exec;
+
+ ira->new_irb.codegen = codegen;
+ ira->new_irb.exec = new_exec;
+
+ ira->exec_context.mem_slot_count = ira->old_irb.exec->mem_slot_count;
+ ira->exec_context.mem_slot_list = allocate<ConstExprValue>(ira->exec_context.mem_slot_count);
+
+ IrBasicBlock *old_entry_bb = ira->old_irb.exec->basic_block_list.at(0);
+ IrBasicBlock *new_entry_bb = ir_get_new_bb(ira, old_entry_bb);
+ ir_ref_bb(new_entry_bb);
+ ira->old_irb.current_basic_block = old_entry_bb;
+ ira->new_irb.current_basic_block = new_entry_bb;
+ ira->block_queue_index = 0;
+ ira->instruction_index = 0;
+
+ while (ira->block_queue_index < ira->old_bb_queue.length) {
+ IrInstruction *old_instruction = ira->old_irb.current_basic_block->instruction_list.at(ira->instruction_index);
+
+ if (old_instruction->ref_count == 0 && !ir_has_side_effects(old_instruction)) {
+ ira->instruction_index += 1;
+ continue;
+ }
+
+ TypeTableEntry *return_type = ir_analyze_instruction(ira, old_instruction);
+
+ // unreachable instructions do their own control flow.
+ if (return_type->id == TypeTableEntryIdUnreachable)
+ continue;
+
+ ira->instruction_index += 1;
+ }
+
+ return ir_resolve_peer_types(ira, expected_type_source_node, ira->implicit_return_type_list.items,
+ ira->implicit_return_type_list.length);
+}
+
+bool ir_has_side_effects(IrInstruction *instruction) {
+ switch (instruction->id) {
+ case IrInstructionIdInvalid:
+ zig_unreachable();
+ case IrInstructionIdBr:
+ case IrInstructionIdCondBr:
case IrInstructionIdSwitchBr:
+ case IrInstructionIdDeclVar:
+ case IrInstructionIdStorePtr:
+ case IrInstructionIdCall:
+ case IrInstructionIdReturn:
+ case IrInstructionIdUnreachable:
+ case IrInstructionIdSetFnTest:
+ return true;
+ case IrInstructionIdPhi:
+ case IrInstructionIdUnOp:
+ case IrInstructionIdBinOp:
+ case IrInstructionIdLoadPtr:
+ case IrInstructionIdConst:
case IrInstructionIdCast:
case IrInstructionIdContainerInitList:
case IrInstructionIdContainerInitFields:
+ case IrInstructionIdFieldPtr:
+ case IrInstructionIdElemPtr:
+ case IrInstructionIdVarPtr:
+ case IrInstructionIdTypeOf:
+ case IrInstructionIdToPtrType:
+ case IrInstructionIdPtrTypeChild:
+ case IrInstructionIdReadField:
case IrInstructionIdStructFieldPtr:
- zig_panic("TODO analyze more instructions");
+ return false;
}
zig_unreachable();
}
-static TypeTableEntry *ir_analyze_instruction(IrAnalyze *ira, IrInstruction *instruction) {
- TypeTableEntry *instruction_type = ir_analyze_instruction_nocast(ira, instruction);
- instruction->type_entry = instruction_type;
- if (instruction->other) {
- instruction->other->type_entry = instruction_type;
- } else {
- assert(instruction_type->id == TypeTableEntryIdInvalid ||
- instruction_type->id == TypeTableEntryIdUnreachable);
- instruction->other = instruction;
- }
- return instruction_type;
-}
-
-// This function attempts to evaluate IR code while doing type checking and other analysis.
-// It emits a new IrExecutable which is partially evaluated IR code.
-TypeTableEntry *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_exec,
- TypeTableEntry *expected_type, AstNode *expected_type_source_node)
-{
- IrAnalyze ir_analyze_data = {};
- IrAnalyze *ira = &ir_analyze_data;
- ira->codegen = codegen;
- ira->explicit_return_type = expected_type;
+IrInstruction *ir_exec_const_result(IrExecutable *exec) {
+ if (exec->basic_block_list.length != 1)
+ return nullptr;
- ira->old_irb.codegen = codegen;
- ira->old_irb.exec = old_exec;
+ IrBasicBlock *bb = exec->basic_block_list.at(0);
+ if (bb->instruction_list.length != 1)
+ return nullptr;
- ira->new_irb.codegen = codegen;
- ira->new_irb.exec = new_exec;
+ IrInstruction *only_inst = bb->instruction_list.at(0);
+ if (only_inst->id != IrInstructionIdReturn)
+ return nullptr;
- ira->exec_context.mem_slot_count = ira->old_irb.exec->mem_slot_count;
- ira->exec_context.mem_slot_list = allocate<ConstExprValue>(ira->exec_context.mem_slot_count);
+ IrInstructionReturn *ret_inst = (IrInstructionReturn *)only_inst;
+ IrInstruction *value = ret_inst->value;
+ assert(value->static_value.ok);
+ return value;
+}
- IrBasicBlock *old_entry_bb = ira->old_irb.exec->basic_block_list.at(0);
- IrBasicBlock *new_entry_bb = ir_get_new_bb(ira, old_entry_bb);
- ir_ref_bb(new_entry_bb);
- ira->old_irb.current_basic_block = old_entry_bb;
- ira->new_irb.current_basic_block = new_entry_bb;
- ira->block_queue_index = 0;
- ira->instruction_index = 0;
+//static TypeTableEntry *analyze_min_max_value(CodeGen *g, ImportTableEntry *import, BlockContext *context,
+// AstNode *node, const char *err_format, bool is_max)
+//{
+// assert(node->type == NodeTypeFnCallExpr);
+// assert(node->data.fn_call_expr.params.length == 1);
+//
+// AstNode *type_node = node->data.fn_call_expr.params.at(0);
+// TypeTableEntry *type_entry = analyze_type_expr(g, import, context, type_node);
+//
+// if (type_entry->id == TypeTableEntryIdInvalid) {
+// return g->builtin_types.entry_invalid;
+// } else if (type_entry->id == TypeTableEntryIdInt) {
+// eval_min_max_value(g, type_entry, &get_resolved_expr(node)->const_val, is_max);
+// return g->builtin_types.entry_num_lit_int;
+// } else if (type_entry->id == TypeTableEntryIdFloat) {
+// eval_min_max_value(g, type_entry, &get_resolved_expr(node)->const_val, is_max);
+// return g->builtin_types.entry_num_lit_float;
+// } else if (type_entry->id == TypeTableEntryIdBool) {
+// eval_min_max_value(g, type_entry, &get_resolved_expr(node)->const_val, is_max);
+// return type_entry;
+// } else {
+// add_node_error(g, node,
+// buf_sprintf(err_format, buf_ptr(&type_entry->name)));
+// return g->builtin_types.entry_invalid;
+// }
+//}
- while (ira->block_queue_index < ira->old_bb_queue.length) {
- IrInstruction *old_instruction = ira->old_irb.current_basic_block->instruction_list.at(ira->instruction_index);
+//static TypeTableEntry *analyze_import(CodeGen *g, ImportTableEntry *import, BlockContext *context,
+// AstNode *node)
+//{
+// assert(node->type == NodeTypeFnCallExpr);
+//
+// if (context->fn_entry) {
+// add_node_error(g, node, buf_sprintf("@import invalid inside function bodies"));
+// return g->builtin_types.entry_invalid;
+// }
+//
+// AstNode *first_param_node = node->data.fn_call_expr.params.at(0);
+// Buf *import_target_str = resolve_const_expr_str(g, import, context, first_param_node->parent_field);
+// if (!import_target_str) {
+// return g->builtin_types.entry_invalid;
+// }
+//
+// Buf *import_target_path;
+// Buf *search_dir;
+// assert(import->package);
+// PackageTableEntry *target_package;
+// auto package_entry = import->package->package_table.maybe_get(import_target_str);
+// if (package_entry) {
+// target_package = package_entry->value;
+// import_target_path = &target_package->root_src_path;
+// search_dir = &target_package->root_src_dir;
+// } else {
+// // try it as a filename
+// target_package = import->package;
+// import_target_path = import_target_str;
+// search_dir = &import->package->root_src_dir;
+// }
+//
+// Buf full_path = BUF_INIT;
+// os_path_join(search_dir, import_target_path, &full_path);
+//
+// Buf *import_code = buf_alloc();
+// Buf *abs_full_path = buf_alloc();
+// int err;
+// if ((err = os_path_real(&full_path, abs_full_path))) {
+// if (err == ErrorFileNotFound) {
+// add_node_error(g, node,
+// buf_sprintf("unable to find '%s'", buf_ptr(import_target_path)));
+// return g->builtin_types.entry_invalid;
+// } else {
+// g->error_during_imports = true;
+// add_node_error(g, node,
+// buf_sprintf("unable to open '%s': %s", buf_ptr(&full_path), err_str(err)));
+// return g->builtin_types.entry_invalid;
+// }
+// }
+//
+// auto import_entry = g->import_table.maybe_get(abs_full_path);
+// if (import_entry) {
+// return resolve_expr_const_val_as_import(g, node, import_entry->value);
+// }
+//
+// if ((err = os_fetch_file_path(abs_full_path, import_code))) {
+// if (err == ErrorFileNotFound) {
+// add_node_error(g, node,
+// buf_sprintf("unable to find '%s'", buf_ptr(import_target_path)));
+// return g->builtin_types.entry_invalid;
+// } else {
+// add_node_error(g, node,
+// buf_sprintf("unable to open '%s': %s", buf_ptr(&full_path), err_str(err)));
+// return g->builtin_types.entry_invalid;
+// }
+// }
+// ImportTableEntry *target_import = add_source_file(g, target_package,
+// abs_full_path, search_dir, import_target_path, import_code);
+//
+// scan_decls(g, target_import, target_import->block_context, target_import->root);
+//
+// return resolve_expr_const_val_as_import(g, node, target_import);
+//}
+//
+//static TypeTableEntry *analyze_c_import(CodeGen *g, ImportTableEntry *parent_import,
+// BlockContext *parent_context, AstNode *node)
+//{
+// assert(node->type == NodeTypeFnCallExpr);
+//
+// if (parent_context->fn_entry) {
+// add_node_error(g, node, buf_sprintf("@c_import invalid inside function bodies"));
+// return g->builtin_types.entry_invalid;
+// }
+//
+// AstNode *block_node = node->data.fn_call_expr.params.at(0);
+//
+// BlockContext *child_context = new_block_context(node, parent_context);
+// child_context->c_import_buf = buf_alloc();
+//
+// TypeTableEntry *resolved_type = analyze_expression(g, parent_import, child_context,
+// g->builtin_types.entry_void, block_node);
+//
+// if (resolved_type->id == TypeTableEntryIdInvalid) {
+// return resolved_type;
+// }
+//
+// find_libc_include_path(g);
+//
+// ImportTableEntry *child_import = allocate<ImportTableEntry>(1);
+// child_import->c_import_node = node;
+//
+// ZigList<ErrorMsg *> errors = {0};
+//
+// int err;
+// if ((err = parse_h_buf(child_import, &errors, child_context->c_import_buf, g, node))) {
+// zig_panic("unable to parse h file: %s\n", err_str(err));
+// }
+//
+// if (errors.length > 0) {
+// ErrorMsg *parent_err_msg = add_node_error(g, node, buf_sprintf("C import failed"));
+// for (size_t i = 0; i < errors.length; i += 1) {
+// ErrorMsg *err_msg = errors.at(i);
+// err_msg_add_note(parent_err_msg, err_msg);
+// }
+//
+// return g->builtin_types.entry_invalid;
+// }
+//
+// if (g->verbose) {
+// fprintf(stderr, "\nc_import:\n");
+// fprintf(stderr, "-----------\n");
+// ast_render(stderr, child_import->root, 4);
+// }
+//
+// child_import->di_file = parent_import->di_file;
+// child_import->block_context = new_block_context(child_import->root, nullptr);
+//
+// scan_decls(g, child_import, child_import->block_context, child_import->root);
+// return resolve_expr_const_val_as_import(g, node, child_import);
+//}
+//
+//static TypeTableEntry *analyze_err_name(CodeGen *g, ImportTableEntry *import,
+// BlockContext *context, AstNode *node)
+//{
+// assert(node->type == NodeTypeFnCallExpr);
+//
+// AstNode *err_value = node->data.fn_call_expr.params.at(0);
+// TypeTableEntry *resolved_type = analyze_expression(g, import, context,
+// g->builtin_types.entry_pure_error, err_value);
+//
+// if (resolved_type->id == TypeTableEntryIdInvalid) {
+// return resolved_type;
+// }
+//
+// g->generate_error_name_table = true;
+//
+// TypeTableEntry *str_type = get_slice_type(g, g->builtin_types.entry_u8, true);
+// return str_type;
+//}
+//
+//static TypeTableEntry *analyze_embed_file(CodeGen *g, ImportTableEntry *import,
+// BlockContext *context, AstNode *node)
+//{
+// assert(node->type == NodeTypeFnCallExpr);
+//
+// AstNode **first_param_node = &node->data.fn_call_expr.params.at(0);
+// Buf *rel_file_path = resolve_const_expr_str(g, import, context, first_param_node);
+// if (!rel_file_path) {
+// return g->builtin_types.entry_invalid;
+// }
+//
+// // figure out absolute path to resource
+// Buf source_dir_path = BUF_INIT;
+// os_path_dirname(import->path, &source_dir_path);
+//
+// Buf file_path = BUF_INIT;
+// os_path_resolve(&source_dir_path, rel_file_path, &file_path);
+//
+// // load from file system into const expr
+// Buf file_contents = BUF_INIT;
+// int err;
+// if ((err = os_fetch_file_path(&file_path, &file_contents))) {
+// if (err == ErrorFileNotFound) {
+// add_node_error(g, node,
+// buf_sprintf("unable to find '%s'", buf_ptr(&file_path)));
+// return g->builtin_types.entry_invalid;
+// } else {
+// add_node_error(g, node,
+// buf_sprintf("unable to open '%s': %s", buf_ptr(&file_path), err_str(err)));
+// return g->builtin_types.entry_invalid;
+// }
+// }
+//
+// // TODO add dependency on the file we embedded so that we know if it changes
+// // we'll have to invalidate the cache
+//
+// return resolve_expr_const_val_as_string_lit(g, node, &file_contents);
+//}
+//
+//static TypeTableEntry *analyze_cmpxchg(CodeGen *g, ImportTableEntry *import,
+// BlockContext *context, AstNode *node)
+//{
+// assert(node->type == NodeTypeFnCallExpr);
+//
+// AstNode **ptr_arg = &node->data.fn_call_expr.params.at(0);
+// AstNode **cmp_arg = &node->data.fn_call_expr.params.at(1);
+// AstNode **new_arg = &node->data.fn_call_expr.params.at(2);
+// AstNode **success_order_arg = &node->data.fn_call_expr.params.at(3);
+// AstNode **failure_order_arg = &node->data.fn_call_expr.params.at(4);
+//
+// TypeTableEntry *ptr_type = analyze_expression(g, import, context, nullptr, *ptr_arg);
+// if (ptr_type->id == TypeTableEntryIdInvalid) {
+// return g->builtin_types.entry_invalid;
+// } else if (ptr_type->id != TypeTableEntryIdPointer) {
+// add_node_error(g, *ptr_arg,
+// buf_sprintf("expected pointer argument, got '%s'", buf_ptr(&ptr_type->name)));
+// return g->builtin_types.entry_invalid;
+// }
+//
+// TypeTableEntry *child_type = ptr_type->data.pointer.child_type;
+// TypeTableEntry *cmp_type = analyze_expression(g, import, context, child_type, *cmp_arg);
+// TypeTableEntry *new_type = analyze_expression(g, import, context, child_type, *new_arg);
+//
+// TypeTableEntry *success_order_type = analyze_expression(g, import, context,
+// g->builtin_types.entry_atomic_order_enum, *success_order_arg);
+// TypeTableEntry *failure_order_type = analyze_expression(g, import, context,
+// g->builtin_types.entry_atomic_order_enum, *failure_order_arg);
+//
+// if (cmp_type->id == TypeTableEntryIdInvalid ||
+// new_type->id == TypeTableEntryIdInvalid ||
+// success_order_type->id == TypeTableEntryIdInvalid ||
+// failure_order_type->id == TypeTableEntryIdInvalid)
+// {
+// return g->builtin_types.entry_invalid;
+// }
+//
+// ConstExprValue *success_order_val = &get_resolved_expr(*success_order_arg)->const_val;
+// ConstExprValue *failure_order_val = &get_resolved_expr(*failure_order_arg)->const_val;
+// if (!success_order_val->ok) {
+// add_node_error(g, *success_order_arg, buf_sprintf("unable to evaluate constant expression"));
+// return g->builtin_types.entry_invalid;
+// } else if (!failure_order_val->ok) {
+// add_node_error(g, *failure_order_arg, buf_sprintf("unable to evaluate constant expression"));
+// return g->builtin_types.entry_invalid;
+// }
+//
+// if (success_order_val->data.x_enum.tag < AtomicOrderMonotonic) {
+// add_node_error(g, *success_order_arg,
+// buf_sprintf("success atomic ordering must be Monotonic or stricter"));
+// return g->builtin_types.entry_invalid;
+// }
+// if (failure_order_val->data.x_enum.tag < AtomicOrderMonotonic) {
+// add_node_error(g, *failure_order_arg,
+// buf_sprintf("failure atomic ordering must be Monotonic or stricter"));
+// return g->builtin_types.entry_invalid;
+// }
+// if (failure_order_val->data.x_enum.tag > success_order_val->data.x_enum.tag) {
+// add_node_error(g, *failure_order_arg,
+// buf_sprintf("failure atomic ordering must be no stricter than success"));
+// return g->builtin_types.entry_invalid;
+// }
+// if (failure_order_val->data.x_enum.tag == AtomicOrderRelease ||
+// failure_order_val->data.x_enum.tag == AtomicOrderAcqRel)
+// {
+// add_node_error(g, *failure_order_arg,
+// buf_sprintf("failure atomic ordering must not be Release or AcqRel"));
+// return g->builtin_types.entry_invalid;
+// }
+//
+// return g->builtin_types.entry_bool;
+//}
+//
+//static TypeTableEntry *analyze_fence(CodeGen *g, ImportTableEntry *import,
+// BlockContext *context, AstNode *node)
+//{
+// assert(node->type == NodeTypeFnCallExpr);
+//
+// AstNode **atomic_order_arg = &node->data.fn_call_expr.params.at(0);
+// TypeTableEntry *atomic_order_type = analyze_expression(g, import, context,
+// g->builtin_types.entry_atomic_order_enum, *atomic_order_arg);
+//
+// if (atomic_order_type->id == TypeTableEntryIdInvalid) {
+// return g->builtin_types.entry_invalid;
+// }
+//
+// ConstExprValue *atomic_order_val = &get_resolved_expr(*atomic_order_arg)->const_val;
+//
+// if (!atomic_order_val->ok) {
+// add_node_error(g, *atomic_order_arg, buf_sprintf("unable to evaluate constant expression"));
+// return g->builtin_types.entry_invalid;
+// }
+//
+// return g->builtin_types.entry_void;
+//}
+//
+//static TypeTableEntry *analyze_div_exact(CodeGen *g, ImportTableEntry *import,
+// BlockContext *context, AstNode *node)
+//{
+// assert(node->type == NodeTypeFnCallExpr);
+//
+// AstNode **op1 = &node->data.fn_call_expr.params.at(0);
+// AstNode **op2 = &node->data.fn_call_expr.params.at(1);
+//
+// TypeTableEntry *op1_type = analyze_expression(g, import, context, nullptr, *op1);
+// TypeTableEntry *op2_type = analyze_expression(g, import, context, nullptr, *op2);
+//
+// AstNode *op_nodes[] = {*op1, *op2};
+// TypeTableEntry *op_types[] = {op1_type, op2_type};
+// TypeTableEntry *result_type = resolve_peer_type_compatibility(g, import, context, node,
+// op_nodes, op_types, 2);
+//
+// if (result_type->id == TypeTableEntryIdInvalid) {
+// return g->builtin_types.entry_invalid;
+// } else if (result_type->id == TypeTableEntryIdInt) {
+// return result_type;
+// } else if (result_type->id == TypeTableEntryIdNumLitInt) {
+// // check for division by zero
+// // check for non exact division
+// zig_panic("TODO");
+// } else {
+// add_node_error(g, node,
+// buf_sprintf("expected integer type, got '%s'", buf_ptr(&result_type->name)));
+// return g->builtin_types.entry_invalid;
+// }
+//}
+//
+//static TypeTableEntry *analyze_truncate(CodeGen *g, ImportTableEntry *import,
+// BlockContext *context, AstNode *node)
+//{
+// assert(node->type == NodeTypeFnCallExpr);
+//
+// AstNode **op1 = &node->data.fn_call_expr.params.at(0);
+// AstNode **op2 = &node->data.fn_call_expr.params.at(1);
+//
+// TypeTableEntry *dest_type = analyze_type_expr(g, import, context, *op1);
+// TypeTableEntry *src_type = analyze_expression(g, import, context, nullptr, *op2);
+//
+// if (dest_type->id == TypeTableEntryIdInvalid || src_type->id == TypeTableEntryIdInvalid) {
+// return g->builtin_types.entry_invalid;
+// } else if (dest_type->id != TypeTableEntryIdInt) {
+// add_node_error(g, *op1,
+// buf_sprintf("expected integer type, got '%s'", buf_ptr(&dest_type->name)));
+// return g->builtin_types.entry_invalid;
+// } else if (src_type->id != TypeTableEntryIdInt) {
+// add_node_error(g, *op2,
+// buf_sprintf("expected integer type, got '%s'", buf_ptr(&src_type->name)));
+// return g->builtin_types.entry_invalid;
+// } else if (src_type->data.integral.is_signed != dest_type->data.integral.is_signed) {
+// const char *sign_str = dest_type->data.integral.is_signed ? "signed" : "unsigned";
+// add_node_error(g, *op2,
+// buf_sprintf("expected %s integer type, got '%s'", sign_str, buf_ptr(&src_type->name)));
+// return g->builtin_types.entry_invalid;
+// } else if (src_type->data.integral.bit_count <= dest_type->data.integral.bit_count) {
+// add_node_error(g, *op2,
+// buf_sprintf("type '%s' has same or fewer bits than destination type '%s'",
+// buf_ptr(&src_type->name), buf_ptr(&dest_type->name)));
+// return g->builtin_types.entry_invalid;
+// }
+//
+// // TODO const expr eval
+//
+// return dest_type;
+//}
+//
+//static TypeTableEntry *analyze_compile_err(CodeGen *g, ImportTableEntry *import,
+// BlockContext *context, AstNode *node)
+//{
+// AstNode *first_param_node = node->data.fn_call_expr.params.at(0);
+// Buf *err_msg = resolve_const_expr_str(g, import, context, first_param_node->parent_field);
+// if (!err_msg) {
+// return g->builtin_types.entry_invalid;
+// }
+//
+// add_node_error(g, node, err_msg);
+//
+// return g->builtin_types.entry_invalid;
+//}
+//
+//static TypeTableEntry *analyze_int_type(CodeGen *g, ImportTableEntry *import,
+// BlockContext *context, AstNode *node)
+//{
+// AstNode **is_signed_node = &node->data.fn_call_expr.params.at(0);
+// AstNode **bit_count_node = &node->data.fn_call_expr.params.at(1);
+//
+// TypeTableEntry *bool_type = g->builtin_types.entry_bool;
+// TypeTableEntry *usize_type = g->builtin_types.entry_usize;
+// TypeTableEntry *is_signed_type = analyze_expression(g, import, context, bool_type, *is_signed_node);
+// TypeTableEntry *bit_count_type = analyze_expression(g, import, context, usize_type, *bit_count_node);
+//
+// if (is_signed_type->id == TypeTableEntryIdInvalid ||
+// bit_count_type->id == TypeTableEntryIdInvalid)
+// {
+// return g->builtin_types.entry_invalid;
+// }
+//
+// ConstExprValue *is_signed_val = &get_resolved_expr(*is_signed_node)->const_val;
+// ConstExprValue *bit_count_val = &get_resolved_expr(*bit_count_node)->const_val;
+//
+// AstNode *bad_node = nullptr;
+// if (!is_signed_val->ok) {
+// bad_node = *is_signed_node;
+// } else if (!bit_count_val->ok) {
+// bad_node = *bit_count_node;
+// }
+// if (bad_node) {
+// add_node_error(g, bad_node, buf_sprintf("unable to evaluate constant expression"));
+// return g->builtin_types.entry_invalid;
+// }
+//
+// bool depends_on_compile_var = is_signed_val->depends_on_compile_var || bit_count_val->depends_on_compile_var;
+//
+// TypeTableEntry *int_type = get_int_type(g, is_signed_val->data.x_bool,
+// bit_count_val->data.x_bignum.data.x_uint);
+// return resolve_expr_const_val_as_type(g, node, int_type, depends_on_compile_var);
+//
+//}
+//
+//static TypeTableEntry *analyze_set_fn_no_inline(CodeGen *g, ImportTableEntry *import,
+// BlockContext *context, AstNode *node)
+//{
+// AstNode **fn_node = &node->data.fn_call_expr.params.at(0);
+// AstNode **value_node = &node->data.fn_call_expr.params.at(1);
+//
+// FnTableEntry *fn_entry = resolve_const_expr_fn(g, import, context, fn_node);
+// if (!fn_entry) {
+// return g->builtin_types.entry_invalid;
+// }
+//
+// bool is_noinline;
+// bool ok = resolve_const_expr_bool(g, import, context, value_node, &is_noinline);
+// if (!ok) {
+// return g->builtin_types.entry_invalid;
+// }
+//
+// if (fn_entry->fn_no_inline_set_node) {
+// ErrorMsg *msg = add_node_error(g, node, buf_sprintf("function no inline attribute set twice"));
+// add_error_note(g, msg, fn_entry->fn_no_inline_set_node, buf_sprintf("first set here"));
+// return g->builtin_types.entry_invalid;
+// }
+// fn_entry->fn_no_inline_set_node = node;
+//
+// if (fn_entry->fn_inline == FnInlineAlways) {
+// add_node_error(g, node, buf_sprintf("function is both inline and noinline"));
+// fn_entry->proto_node->data.fn_proto.skip = true;
+// return g->builtin_types.entry_invalid;
+// } else if (is_noinline) {
+// fn_entry->fn_inline = FnInlineNever;
+// }
+//
+// return g->builtin_types.entry_void;
+//}
+//
+//static TypeTableEntry *analyze_set_fn_static_eval(CodeGen *g, ImportTableEntry *import,
+// BlockContext *context, AstNode *node)
+//{
+// AstNode **fn_node = &node->data.fn_call_expr.params.at(0);
+// AstNode **value_node = &node->data.fn_call_expr.params.at(1);
+//
+// FnTableEntry *fn_entry = resolve_const_expr_fn(g, import, context, fn_node);
+// if (!fn_entry) {
+// return g->builtin_types.entry_invalid;
+// }
+//
+// bool want_static_eval;
+// bool ok = resolve_const_expr_bool(g, import, context, value_node, &want_static_eval);
+// if (!ok) {
+// return g->builtin_types.entry_invalid;
+// }
+//
+// if (fn_entry->fn_static_eval_set_node) {
+// ErrorMsg *msg = add_node_error(g, node, buf_sprintf("function static eval attribute set twice"));
+// add_error_note(g, msg, fn_entry->fn_static_eval_set_node, buf_sprintf("first set here"));
+// return g->builtin_types.entry_invalid;
+// }
+// fn_entry->fn_static_eval_set_node = node;
+//
+// if (want_static_eval && !context->fn_entry->is_pure) {
+// add_node_error(g, node, buf_sprintf("attribute appears too late within function"));
+// return g->builtin_types.entry_invalid;
+// }
+//
+// if (want_static_eval) {
+// fn_entry->want_pure = WantPureTrue;
+// fn_entry->want_pure_attr_node = node;
+// } else {
+// fn_entry->want_pure = WantPureFalse;
+// fn_entry->is_pure = false;
+// }
+//
+// return g->builtin_types.entry_void;
+//}
+//
+//static TypeTableEntry *analyze_set_fn_visible(CodeGen *g, ImportTableEntry *import,
+// BlockContext *context, AstNode *node)
+//{
+// AstNode **fn_node = &node->data.fn_call_expr.params.at(0);
+// AstNode **value_node = &node->data.fn_call_expr.params.at(1);
+//
+// FnTableEntry *fn_entry = resolve_const_expr_fn(g, import, context, fn_node);
+// if (!fn_entry) {
+// return g->builtin_types.entry_invalid;
+// }
+//
+// bool want_export;
+// bool ok = resolve_const_expr_bool(g, import, context, value_node, &want_export);
+// if (!ok) {
+// return g->builtin_types.entry_invalid;
+// }
+//
+// if (fn_entry->fn_export_set_node) {
+// ErrorMsg *msg = add_node_error(g, node, buf_sprintf("function visibility set twice"));
+// add_error_note(g, msg, fn_entry->fn_export_set_node, buf_sprintf("first set here"));
+// return g->builtin_types.entry_invalid;
+// }
+// fn_entry->fn_export_set_node = node;
+//
+// AstNodeFnProto *fn_proto = &fn_entry->proto_node->data.fn_proto;
+// if (fn_proto->top_level_decl.visib_mod != VisibModExport) {
+// ErrorMsg *msg = add_node_error(g, node,
+// buf_sprintf("function must be marked export to set function visibility"));
+// add_error_note(g, msg, fn_entry->proto_node, buf_sprintf("function declared here"));
+// return g->builtin_types.entry_void;
+// }
+// if (!want_export) {
+// fn_proto->top_level_decl.visib_mod = VisibModPub;
+// }
+//
+// return g->builtin_types.entry_void;
+//}
+//
+//static TypeTableEntry *analyze_set_debug_safety(CodeGen *g, ImportTableEntry *import,
+// BlockContext *parent_context, AstNode *node)
+//{
+// AstNode **target_node = &node->data.fn_call_expr.params.at(0);
+// AstNode **value_node = &node->data.fn_call_expr.params.at(1);
+//
+// TypeTableEntry *target_type = analyze_expression(g, import, parent_context, nullptr, *target_node);
+// BlockContext *target_context;
+// ConstExprValue *const_val = &get_resolved_expr(*target_node)->const_val;
+// if (target_type->id == TypeTableEntryIdInvalid) {
+// return g->builtin_types.entry_invalid;
+// }
+// if (!const_val->ok) {
+// add_node_error(g, *target_node, buf_sprintf("unable to evaluate constant expression"));
+// return g->builtin_types.entry_invalid;
+// }
+// if (target_type->id == TypeTableEntryIdBlock) {
+// target_context = const_val->data.x_block;
+// } else if (target_type->id == TypeTableEntryIdFn) {
+// target_context = const_val->data.x_fn->fn_def_node->data.fn_def.block_context;
+// } else if (target_type->id == TypeTableEntryIdMetaType) {
+// TypeTableEntry *type_arg = const_val->data.x_type;
+// if (type_arg->id == TypeTableEntryIdStruct) {
+// target_context = type_arg->data.structure.block_context;
+// } else if (type_arg->id == TypeTableEntryIdEnum) {
+// target_context = type_arg->data.enumeration.block_context;
+// } else if (type_arg->id == TypeTableEntryIdUnion) {
+// target_context = type_arg->data.unionation.block_context;
+// } else {
+// add_node_error(g, *target_node,
+// buf_sprintf("expected scope reference, got type '%s'", buf_ptr(&type_arg->name)));
+// return g->builtin_types.entry_invalid;
+// }
+// } else {
+// add_node_error(g, *target_node,
+// buf_sprintf("expected scope reference, got type '%s'", buf_ptr(&target_type->name)));
+// return g->builtin_types.entry_invalid;
+// }
+//
+// bool want_debug_safety;
+// bool ok = resolve_const_expr_bool(g, import, parent_context, value_node, &want_debug_safety);
+// if (!ok) {
+// return g->builtin_types.entry_invalid;
+// }
+//
+// if (target_context->safety_set_node) {
+// ErrorMsg *msg = add_node_error(g, node, buf_sprintf("debug safety for scope set twice"));
+// add_error_note(g, msg, target_context->safety_set_node, buf_sprintf("first set here"));
+// return g->builtin_types.entry_invalid;
+// }
+// target_context->safety_set_node = node;
+//
+// target_context->safety_off = !want_debug_safety;
+//
+// return g->builtin_types.entry_void;
+//}
- if (old_instruction->ref_count == 0 && !ir_has_side_effects(old_instruction)) {
- ira->instruction_index += 1;
- continue;
- }
- TypeTableEntry *return_type = ir_analyze_instruction(ira, old_instruction);
+//static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
+// TypeTableEntry *expected_type, AstNode *node)
+//{
+//
+// switch (builtin_fn->id) {
+// case BuiltinFnIdInvalid:
+// zig_unreachable();
+// case BuiltinFnIdAddWithOverflow:
+// case BuiltinFnIdSubWithOverflow:
+// case BuiltinFnIdMulWithOverflow:
+// case BuiltinFnIdShlWithOverflow:
+// {
+// AstNode *type_node = node->data.fn_call_expr.params.at(0);
+// TypeTableEntry *int_type = analyze_type_expr(g, import, context, type_node);
+// if (int_type->id == TypeTableEntryIdInvalid) {
+// return g->builtin_types.entry_bool;
+// } else if (int_type->id == TypeTableEntryIdInt) {
+// AstNode *op1_node = node->data.fn_call_expr.params.at(1);
+// AstNode *op2_node = node->data.fn_call_expr.params.at(2);
+// AstNode *result_node = node->data.fn_call_expr.params.at(3);
+//
+// analyze_expression(g, import, context, int_type, op1_node);
+// analyze_expression(g, import, context, int_type, op2_node);
+// analyze_expression(g, import, context, get_pointer_to_type(g, int_type, false),
+// result_node);
+// } else {
+// add_node_error(g, type_node,
+// buf_sprintf("expected integer type, got '%s'", buf_ptr(&int_type->name)));
+// }
+//
+// // TODO constant expression evaluation
+//
+// return g->builtin_types.entry_bool;
+// }
+// case BuiltinFnIdMemcpy:
+// {
+// AstNode *dest_node = node->data.fn_call_expr.params.at(0);
+// AstNode *src_node = node->data.fn_call_expr.params.at(1);
+// AstNode *len_node = node->data.fn_call_expr.params.at(2);
+// TypeTableEntry *dest_type = analyze_expression(g, import, context, nullptr, dest_node);
+// TypeTableEntry *src_type = analyze_expression(g, import, context, nullptr, src_node);
+// analyze_expression(g, import, context, builtin_fn->param_types[2], len_node);
+//
+// if (dest_type->id != TypeTableEntryIdInvalid &&
+// dest_type->id != TypeTableEntryIdPointer)
+// {
+// add_node_error(g, dest_node,
+// buf_sprintf("expected pointer argument, got '%s'", buf_ptr(&dest_type->name)));
+// }
+//
+// if (src_type->id != TypeTableEntryIdInvalid &&
+// src_type->id != TypeTableEntryIdPointer)
+// {
+// add_node_error(g, src_node,
+// buf_sprintf("expected pointer argument, got '%s'", buf_ptr(&src_type->name)));
+// }
+//
+// if (dest_type->id == TypeTableEntryIdPointer &&
+// src_type->id == TypeTableEntryIdPointer)
+// {
+// uint64_t dest_align = get_memcpy_align(g, dest_type->data.pointer.child_type);
+// uint64_t src_align = get_memcpy_align(g, src_type->data.pointer.child_type);
+// if (dest_align != src_align) {
+// add_node_error(g, dest_node, buf_sprintf(
+// "misaligned memcpy, '%s' has alignment '%" PRIu64 ", '%s' has alignment %" PRIu64,
+// buf_ptr(&dest_type->name), dest_align,
+// buf_ptr(&src_type->name), src_align));
+// }
+// }
+//
+// return builtin_fn->return_type;
+// }
+// case BuiltinFnIdMemset:
+// {
+// AstNode *dest_node = node->data.fn_call_expr.params.at(0);
+// AstNode *char_node = node->data.fn_call_expr.params.at(1);
+// AstNode *len_node = node->data.fn_call_expr.params.at(2);
+// TypeTableEntry *dest_type = analyze_expression(g, import, context, nullptr, dest_node);
+// analyze_expression(g, import, context, builtin_fn->param_types[1], char_node);
+// analyze_expression(g, import, context, builtin_fn->param_types[2], len_node);
+//
+// if (dest_type->id != TypeTableEntryIdInvalid &&
+// dest_type->id != TypeTableEntryIdPointer)
+// {
+// add_node_error(g, dest_node,
+// buf_sprintf("expected pointer argument, got '%s'", buf_ptr(&dest_type->name)));
+// }
+//
+// return builtin_fn->return_type;
+// }
+// case BuiltinFnIdSizeof:
+// {
+// AstNode *type_node = node->data.fn_call_expr.params.at(0);
+// TypeTableEntry *type_entry = analyze_type_expr(g, import, context, type_node);
+// if (type_entry->id == TypeTableEntryIdInvalid) {
+// return g->builtin_types.entry_invalid;
+// } else if (type_entry->id == TypeTableEntryIdUnreachable) {
+// add_node_error(g, first_executing_node(type_node),
+// buf_sprintf("no size available for type '%s'", buf_ptr(&type_entry->name)));
+// return g->builtin_types.entry_invalid;
+// } else {
+// uint64_t size_in_bytes = type_size(g, type_entry);
+// bool depends_on_compile_var = (type_entry == g->builtin_types.entry_usize ||
+// type_entry == g->builtin_types.entry_isize);
+// return resolve_expr_const_val_as_unsigned_num_lit(g, node, expected_type,
+// size_in_bytes, depends_on_compile_var);
+// }
+// }
+// case BuiltinFnIdAlignof:
+// {
+// AstNode *type_node = node->data.fn_call_expr.params.at(0);
+// TypeTableEntry *type_entry = analyze_type_expr(g, import, context, type_node);
+// if (type_entry->id == TypeTableEntryIdInvalid) {
+// return g->builtin_types.entry_invalid;
+// } else if (type_entry->id == TypeTableEntryIdUnreachable) {
+// add_node_error(g, first_executing_node(type_node),
+// buf_sprintf("no align available for type '%s'", buf_ptr(&type_entry->name)));
+// return g->builtin_types.entry_invalid;
+// } else {
+// uint64_t align_in_bytes = LLVMABISizeOfType(g->target_data_ref, type_entry->type_ref);
+// return resolve_expr_const_val_as_unsigned_num_lit(g, node, expected_type,
+// align_in_bytes, false);
+// }
+// }
+// case BuiltinFnIdMaxValue:
+// return analyze_min_max_value(g, import, context, node,
+// "no max value available for type '%s'", true);
+// case BuiltinFnIdMinValue:
+// return analyze_min_max_value(g, import, context, node,
+// "no min value available for type '%s'", false);
+// case BuiltinFnIdMemberCount:
+// {
+// AstNode *type_node = node->data.fn_call_expr.params.at(0);
+// TypeTableEntry *type_entry = analyze_type_expr(g, import, context, type_node);
+//
+// if (type_entry->id == TypeTableEntryIdInvalid) {
+// return type_entry;
+// } else if (type_entry->id == TypeTableEntryIdEnum) {
+// uint64_t value_count = type_entry->data.enumeration.src_field_count;
+// return resolve_expr_const_val_as_unsigned_num_lit(g, node, expected_type,
+// value_count, false);
+// } else {
+// add_node_error(g, node,
+// buf_sprintf("no value count available for type '%s'", buf_ptr(&type_entry->name)));
+// return g->builtin_types.entry_invalid;
+// }
+// }
+// case BuiltinFnIdCInclude:
+// {
+// if (!context->c_import_buf) {
+// add_node_error(g, node, buf_sprintf("@c_include valid only in c_import blocks"));
+// return g->builtin_types.entry_invalid;
+// }
+//
+// AstNode **str_node = node->data.fn_call_expr.params.at(0)->parent_field;
+// TypeTableEntry *str_type = get_slice_type(g, g->builtin_types.entry_u8, true);
+// TypeTableEntry *resolved_type = analyze_expression(g, import, context, str_type, *str_node);
+//
+// if (resolved_type->id == TypeTableEntryIdInvalid) {
+// return resolved_type;
+// }
+//
+// ConstExprValue *const_str_val = &get_resolved_expr(*str_node)->const_val;
+//
+// if (!const_str_val->ok) {
+// add_node_error(g, *str_node, buf_sprintf("@c_include requires constant expression"));
+// return g->builtin_types.entry_void;
+// }
+//
+// buf_appendf(context->c_import_buf, "#include <");
+// ConstExprValue *ptr_field = const_str_val->data.x_struct.fields[0];
+// uint64_t len = ptr_field->data.x_ptr.len;
+// for (uint64_t i = 0; i < len; i += 1) {
+// ConstExprValue *char_val = ptr_field->data.x_ptr.ptr[i];
+// uint64_t big_c = char_val->data.x_bignum.data.x_uint;
+// assert(big_c <= UINT8_MAX);
+// uint8_t c = big_c;
+// buf_append_char(context->c_import_buf, c);
+// }
+// buf_appendf(context->c_import_buf, ">\n");
+//
+// return g->builtin_types.entry_void;
+// }
+// case BuiltinFnIdCDefine:
+// zig_panic("TODO");
+// case BuiltinFnIdCUndef:
+// zig_panic("TODO");
+//
+// case BuiltinFnIdCompileVar:
+// {
+// AstNode **str_node = node->data.fn_call_expr.params.at(0)->parent_field;
+//
+// Buf *var_name = resolve_const_expr_str(g, import, context, str_node);
+// if (!var_name) {
+// return g->builtin_types.entry_invalid;
+// }
+//
+// ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
+// const_val->ok = true;
+// const_val->depends_on_compile_var = true;
+//
+// if (buf_eql_str(var_name, "is_big_endian")) {
+// return resolve_expr_const_val_as_bool(g, node, g->is_big_endian, true);
+// } else if (buf_eql_str(var_name, "is_release")) {
+// return resolve_expr_const_val_as_bool(g, node, g->is_release_build, true);
+// } else if (buf_eql_str(var_name, "is_test")) {
+// return resolve_expr_const_val_as_bool(g, node, g->is_test_build, true);
+// } else if (buf_eql_str(var_name, "os")) {
+// const_val->data.x_enum.tag = g->target_os_index;
+// return g->builtin_types.entry_os_enum;
+// } else if (buf_eql_str(var_name, "arch")) {
+// const_val->data.x_enum.tag = g->target_arch_index;
+// return g->builtin_types.entry_arch_enum;
+// } else if (buf_eql_str(var_name, "environ")) {
+// const_val->data.x_enum.tag = g->target_environ_index;
+// return g->builtin_types.entry_environ_enum;
+// } else if (buf_eql_str(var_name, "object_format")) {
+// const_val->data.x_enum.tag = g->target_oformat_index;
+// return g->builtin_types.entry_oformat_enum;
+// } else {
+// add_node_error(g, *str_node,
+// buf_sprintf("unrecognized compile variable: '%s'", buf_ptr(var_name)));
+// return g->builtin_types.entry_invalid;
+// }
+// }
+// case BuiltinFnIdConstEval:
+// {
+// AstNode **expr_node = node->data.fn_call_expr.params.at(0)->parent_field;
+// TypeTableEntry *resolved_type = analyze_expression(g, import, context, expected_type, *expr_node);
+// if (resolved_type->id == TypeTableEntryIdInvalid) {
+// return resolved_type;
+// }
+//
+// ConstExprValue *const_expr_val = &get_resolved_expr(*expr_node)->const_val;
+//
+// if (!const_expr_val->ok) {
+// add_node_error(g, *expr_node, buf_sprintf("unable to evaluate constant expression"));
+// return g->builtin_types.entry_invalid;
+// }
+//
+// ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
+// *const_val = *const_expr_val;
+//
+// return resolved_type;
+// }
+// case BuiltinFnIdCtz:
+// case BuiltinFnIdClz:
+// {
+// AstNode *type_node = node->data.fn_call_expr.params.at(0);
+// TypeTableEntry *int_type = analyze_type_expr(g, import, context, type_node);
+// if (int_type->id == TypeTableEntryIdInvalid) {
+// return int_type;
+// } else if (int_type->id == TypeTableEntryIdInt) {
+// AstNode **expr_node = node->data.fn_call_expr.params.at(1)->parent_field;
+// TypeTableEntry *resolved_type = analyze_expression(g, import, context, int_type, *expr_node);
+// if (resolved_type->id == TypeTableEntryIdInvalid) {
+// return resolved_type;
+// }
+//
+// // TODO const expr eval
+//
+// return resolved_type;
+// } else {
+// add_node_error(g, type_node,
+// buf_sprintf("expected integer type, got '%s'", buf_ptr(&int_type->name)));
+// return g->builtin_types.entry_invalid;
+// }
+// }
+// case BuiltinFnIdImport:
+// return analyze_import(g, import, context, node);
+// case BuiltinFnIdCImport:
+// return analyze_c_import(g, import, context, node);
+// case BuiltinFnIdErrName:
+// return analyze_err_name(g, import, context, node);
+// case BuiltinFnIdBreakpoint:
+// mark_impure_fn(g, context, node);
+// return g->builtin_types.entry_void;
+// case BuiltinFnIdReturnAddress:
+// case BuiltinFnIdFrameAddress:
+// mark_impure_fn(g, context, node);
+// return builtin_fn->return_type;
+// case BuiltinFnIdEmbedFile:
+// return analyze_embed_file(g, import, context, node);
+// case BuiltinFnIdCmpExchange:
+// return analyze_cmpxchg(g, import, context, node);
+// case BuiltinFnIdFence:
+// return analyze_fence(g, import, context, node);
+// case BuiltinFnIdDivExact:
+// return analyze_div_exact(g, import, context, node);
+// case BuiltinFnIdTruncate:
+// return analyze_truncate(g, import, context, node);
+// case BuiltinFnIdCompileErr:
+// return analyze_compile_err(g, import, context, node);
+// case BuiltinFnIdIntType:
+// return analyze_int_type(g, import, context, node);
+// case BuiltinFnIdSetFnTest:
+// return analyze_set_fn_test(g, import, context, node);
+// case BuiltinFnIdSetFnNoInline:
+// return analyze_set_fn_no_inline(g, import, context, node);
+// case BuiltinFnIdSetFnStaticEval:
+// return analyze_set_fn_static_eval(g, import, context, node);
+// case BuiltinFnIdSetFnVisible:
+// return analyze_set_fn_visible(g, import, context, node);
+// case BuiltinFnIdSetDebugSafety:
+// return analyze_set_debug_safety(g, import, context, node);
+// }
+// zig_unreachable();
+//}
- // unreachable instructions do their own control flow.
- if (return_type->id == TypeTableEntryIdUnreachable)
- continue;
+//static TypeTableEntry *analyze_container_init_expr(CodeGen *g, ImportTableEntry *import,
+// BlockContext *context, AstNode *node)
+//{
+// assert(node->type == NodeTypeContainerInitExpr);
+//
+// AstNodeContainerInitExpr *container_init_expr = &node->data.container_init_expr;
+//
+// ContainerInitKind kind = container_init_expr->kind;
+//
+// if (container_init_expr->type->type == NodeTypeFieldAccessExpr) {
+// container_init_expr->type->data.field_access_expr.container_init_expr_node = node;
+// }
+//
+// TypeTableEntry *container_meta_type = analyze_expression(g, import, context, nullptr,
+// container_init_expr->type);
+//
+// if (container_meta_type->id == TypeTableEntryIdInvalid) {
+// return g->builtin_types.entry_invalid;
+// }
+//
+// if (node->data.container_init_expr.enum_type) {
+// get_resolved_expr(node)->const_val = get_resolved_expr(container_init_expr->type)->const_val;
+// return node->data.container_init_expr.enum_type;
+// }
+//
+// TypeTableEntry *container_type = resolve_type(g, container_init_expr->type);
+//
+// if (container_type->id == TypeTableEntryIdInvalid) {
+// return container_type;
+// } else if (container_type->id == TypeTableEntryIdStruct &&
+// !container_type->data.structure.is_slice &&
+// (kind == ContainerInitKindStruct || (kind == ContainerInitKindArray &&
+// container_init_expr->entries.length == 0)))
+// {
+// StructValExprCodeGen *codegen = &container_init_expr->resolved_struct_val_expr;
+// codegen->type_entry = container_type;
+// codegen->source_node = node;
+//
+//
+// size_t expr_field_count = container_init_expr->entries.length;
+// size_t actual_field_count = container_type->data.structure.src_field_count;
+//
+// AstNode *non_const_expr_culprit = nullptr;
+//
+// size_t *field_use_counts = allocate<size_t>(actual_field_count);
+// ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
+// const_val->ok = true;
+// const_val->data.x_struct.fields = allocate<ConstExprValue*>(actual_field_count);
+// for (size_t i = 0; i < expr_field_count; i += 1) {
+// AstNode *val_field_node = container_init_expr->entries.at(i);
+// assert(val_field_node->type == NodeTypeStructValueField);
+//
+// val_field_node->block_context = context;
+//
+// TypeStructField *type_field = find_struct_type_field(container_type,
+// val_field_node->data.struct_val_field.name);
+//
+// if (!type_field) {
+// add_node_error(g, val_field_node,
+// buf_sprintf("no member named '%s' in '%s'",
+// buf_ptr(val_field_node->data.struct_val_field.name), buf_ptr(&container_type->name)));
+// continue;
+// }
+//
+// if (type_field->type_entry->id == TypeTableEntryIdInvalid) {
+// return g->builtin_types.entry_invalid;
+// }
+//
+// size_t field_index = type_field->src_index;
+// field_use_counts[field_index] += 1;
+// if (field_use_counts[field_index] > 1) {
+// add_node_error(g, val_field_node, buf_sprintf("duplicate field"));
+// continue;
+// }
+//
+// val_field_node->data.struct_val_field.type_struct_field = type_field;
+//
+// analyze_expression(g, import, context, type_field->type_entry,
+// val_field_node->data.struct_val_field.expr);
+//
+// if (const_val->ok) {
+// ConstExprValue *field_val =
+// &get_resolved_expr(val_field_node->data.struct_val_field.expr)->const_val;
+// if (field_val->ok) {
+// const_val->data.x_struct.fields[field_index] = field_val;
+// const_val->depends_on_compile_var = const_val->depends_on_compile_var || field_val->depends_on_compile_var;
+// } else {
+// const_val->ok = false;
+// non_const_expr_culprit = val_field_node->data.struct_val_field.expr;
+// }
+// }
+// }
+// if (!const_val->ok) {
+// assert(non_const_expr_culprit);
+// if (context->fn_entry) {
+// context->fn_entry->struct_val_expr_alloca_list.append(codegen);
+// } else {
+// add_node_error(g, non_const_expr_culprit, buf_sprintf("unable to evaluate constant expression"));
+// }
+// }
+//
+// for (size_t i = 0; i < actual_field_count; i += 1) {
+// if (field_use_counts[i] == 0) {
+// add_node_error(g, node,
+// buf_sprintf("missing field: '%s'", buf_ptr(container_type->data.structure.fields[i].name)));
+// }
+// }
+// return container_type;
+// } else if (container_type->id == TypeTableEntryIdStruct &&
+// container_type->data.structure.is_slice &&
+// kind == ContainerInitKindArray)
+// {
+// size_t elem_count = container_init_expr->entries.length;
+//
+// TypeTableEntry *pointer_type = container_type->data.structure.fields[0].type_entry;
+// assert(pointer_type->id == TypeTableEntryIdPointer);
+// TypeTableEntry *child_type = pointer_type->data.pointer.child_type;
+//
+// ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
+// const_val->ok = true;
+// const_val->data.x_array.fields = allocate<ConstExprValue*>(elem_count);
+//
+// for (size_t i = 0; i < elem_count; i += 1) {
+// AstNode **elem_node = &container_init_expr->entries.at(i);
+// analyze_expression(g, import, context, child_type, *elem_node);
+//
+// if (const_val->ok) {
+// ConstExprValue *elem_const_val = &get_resolved_expr(*elem_node)->const_val;
+// if (elem_const_val->ok) {
+// const_val->data.x_array.fields[i] = elem_const_val;
+// const_val->depends_on_compile_var = const_val->depends_on_compile_var ||
+// elem_const_val->depends_on_compile_var;
+// } else {
+// const_val->ok = false;
+// }
+// }
+// }
+//
+// TypeTableEntry *fixed_size_array_type = get_array_type(g, child_type, elem_count);
+//
+// StructValExprCodeGen *codegen = &container_init_expr->resolved_struct_val_expr;
+// codegen->type_entry = fixed_size_array_type;
+// codegen->source_node = node;
+// if (!const_val->ok) {
+// if (!context->fn_entry) {
+// add_node_error(g, node,
+// buf_sprintf("unable to evaluate constant expression"));
+// } else {
+// context->fn_entry->struct_val_expr_alloca_list.append(codegen);
+// }
+// }
+//
+// return fixed_size_array_type;
+// } else if (container_type->id == TypeTableEntryIdArray) {
+// zig_panic("TODO array container init");
+// return container_type;
+// } else if (container_type->id == TypeTableEntryIdVoid) {
+// if (container_init_expr->entries.length != 0) {
+// add_node_error(g, node, buf_sprintf("void expression expects no arguments"));
+// return g->builtin_types.entry_invalid;
+// } else {
+// return resolve_expr_const_val_as_void(g, node);
+// }
+// } else {
+// add_node_error(g, node,
+// buf_sprintf("type '%s' does not support %s initialization syntax",
+// buf_ptr(&container_type->name), err_container_init_syntax_name(kind)));
+// return g->builtin_types.entry_invalid;
+// }
+//}
- ira->instruction_index += 1;
- }
- return ir_resolve_peer_types(ira, expected_type_source_node, ira->implicit_return_type_list.items,
- ira->implicit_return_type_list.length);
-}
-static bool ir_builtin_call_has_side_effects(IrInstructionBuiltinCall *call_instruction) {
- switch (call_instruction->fn->id) {
- case BuiltinFnIdInvalid:
- zig_unreachable();
- case BuiltinFnIdMemcpy:
- case BuiltinFnIdMemset:
- case BuiltinFnIdAddWithOverflow:
- case BuiltinFnIdSubWithOverflow:
- case BuiltinFnIdMulWithOverflow:
- case BuiltinFnIdShlWithOverflow:
- case BuiltinFnIdCInclude:
- case BuiltinFnIdCDefine:
- case BuiltinFnIdCUndef:
- case BuiltinFnIdImport:
- case BuiltinFnIdCImport:
- case BuiltinFnIdBreakpoint:
- case BuiltinFnIdEmbedFile:
- case BuiltinFnIdCmpExchange:
- case BuiltinFnIdFence:
- case BuiltinFnIdUnreachable:
- case BuiltinFnIdSetFnTest:
- case BuiltinFnIdSetFnVisible:
- case BuiltinFnIdSetFnStaticEval:
- case BuiltinFnIdSetFnNoInline:
- case BuiltinFnIdSetDebugSafety:
- return true;
- case BuiltinFnIdSizeof:
- case BuiltinFnIdAlignof:
- case BuiltinFnIdMaxValue:
- case BuiltinFnIdMinValue:
- case BuiltinFnIdMemberCount:
- case BuiltinFnIdTypeof:
- case BuiltinFnIdCompileVar:
- case BuiltinFnIdCompileErr:
- case BuiltinFnIdConstEval:
- case BuiltinFnIdCtz:
- case BuiltinFnIdClz:
- case BuiltinFnIdErrName:
- case BuiltinFnIdReturnAddress:
- case BuiltinFnIdFrameAddress:
- case BuiltinFnIdDivExact:
- case BuiltinFnIdTruncate:
- case BuiltinFnIdIntType:
- return false;
- }
- zig_unreachable();
-}
+//static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
+// TypeTableEntry *expected_type, AstNode *node)
+//{
+// assert(node->type == NodeTypeFieldAccessExpr);
+//
+// AstNode **struct_expr_node = &node->data.field_access_expr.struct_expr;
+// TypeTableEntry *struct_type = analyze_expression(g, import, context, nullptr, *struct_expr_node);
+// Buf *field_name = node->data.field_access_expr.field_name;
+//
+// if (struct_type->id == TypeTableEntryIdInvalid) {
+// return struct_type;
+// } else if (is_container_ref(struct_type)) {
+// return analyze_container_member_access(g, field_name, node, struct_type);
+// } else if (struct_type->id == TypeTableEntryIdArray) {
+// if (buf_eql_str(field_name, "len")) {
+// return resolve_expr_const_val_as_unsigned_num_lit(g, node, expected_type,
+// struct_type->data.array.len, false);
+// } else {
+// add_node_error(g, node,
+// buf_sprintf("no member named '%s' in '%s'", buf_ptr(field_name),
+// buf_ptr(&struct_type->name)));
+// return g->builtin_types.entry_invalid;
+// }
+// } else if (struct_type->id == TypeTableEntryIdMetaType) {
+// TypeTableEntry *child_type = resolve_type(g, *struct_expr_node);
+//
+// if (child_type->id == TypeTableEntryIdInvalid) {
+// return g->builtin_types.entry_invalid;
+// } else if (child_type->id == TypeTableEntryIdEnum) {
+// AstNode *container_init_node = node->data.field_access_expr.container_init_expr_node;
+// AstNode *value_node;
+// if (container_init_node) {
+// assert(container_init_node->type == NodeTypeContainerInitExpr);
+// size_t param_count = container_init_node->data.container_init_expr.entries.length;
+// if (param_count > 1) {
+// AstNode *first_invalid_node = container_init_node->data.container_init_expr.entries.at(1);
+// add_node_error(g, first_executing_node(first_invalid_node),
+// buf_sprintf("enum values accept only one parameter"));
+// return child_type;
+// } else {
+// if (param_count == 1) {
+// value_node = container_init_node->data.container_init_expr.entries.at(0);
+// } else {
+// value_node = nullptr;
+// }
+// container_init_node->data.container_init_expr.enum_type = child_type;
+// }
+// } else {
+// value_node = nullptr;
+// }
+// return analyze_enum_value_expr(g, import, context, node, value_node, child_type, field_name, node);
+// } else if (child_type->id == TypeTableEntryIdStruct) {
+// BlockContext *container_block_context = get_container_block_context(child_type);
+// auto entry = container_block_context->decl_table.maybe_get(field_name);
+// AstNode *decl_node = entry ? entry->value : nullptr;
+// if (decl_node) {
+// bool pointer_only = false;
+// return analyze_decl_ref(g, node, decl_node, pointer_only, context, false);
+// } else {
+// add_node_error(g, node,
+// buf_sprintf("container '%s' has no member called '%s'",
+// buf_ptr(&child_type->name), buf_ptr(field_name)));
+// return g->builtin_types.entry_invalid;
+// }
+// } else if (child_type->id == TypeTableEntryIdPureError) {
+// return analyze_error_literal_expr(g, import, context, node, field_name);
+// } else if (child_type->id == TypeTableEntryIdInt) {
+// bool depends_on_compile_var =
+// get_resolved_expr(*struct_expr_node)->const_val.depends_on_compile_var;
+// if (buf_eql_str(field_name, "bit_count")) {
+// return resolve_expr_const_val_as_unsigned_num_lit(g, node, expected_type,
+// child_type->data.integral.bit_count, depends_on_compile_var);
+// } else if (buf_eql_str(field_name, "is_signed")) {
+// return resolve_expr_const_val_as_bool(g, node, child_type->data.integral.is_signed,
+// depends_on_compile_var);
+// } else {
+// add_node_error(g, node,
+// buf_sprintf("type '%s' has no member called '%s'",
+// buf_ptr(&child_type->name), buf_ptr(field_name)));
+// return g->builtin_types.entry_invalid;
+// }
+// } else {
+// add_node_error(g, node,
+// buf_sprintf("type '%s' does not support field access", buf_ptr(&struct_type->name)));
+// return g->builtin_types.entry_invalid;
+// }
+// } else if (struct_type->id == TypeTableEntryIdNamespace) {
+// ConstExprValue *const_val = &get_resolved_expr(*struct_expr_node)->const_val;
+// assert(const_val->ok);
+// ImportTableEntry *namespace_import = const_val->data.x_import;
+// AstNode *decl_node = find_decl(namespace_import->block_context, field_name);
+// if (!decl_node) {
+// // we must now resolve all the use decls
+// for (size_t i = 0; i < namespace_import->use_decls.length; i += 1) {
+// AstNode *use_decl_node = namespace_import->use_decls.at(i);
+// if (!get_resolved_expr(use_decl_node->data.use.expr)->type_entry) {
+// preview_use_decl(g, use_decl_node);
+// }
+// resolve_use_decl(g, use_decl_node);
+// }
+// decl_node = find_decl(namespace_import->block_context, field_name);
+// }
+// if (decl_node) {
+// TopLevelDecl *tld = get_as_top_level_decl(decl_node);
+// if (tld->visib_mod == VisibModPrivate && decl_node->owner != import) {
+// ErrorMsg *msg = add_node_error(g, node,
+// buf_sprintf("'%s' is private", buf_ptr(field_name)));
+// add_error_note(g, msg, decl_node, buf_sprintf("declared here"));
+// }
+// bool pointer_only = false;
+// return analyze_decl_ref(g, node, decl_node, pointer_only, context,
+// const_val->depends_on_compile_var);
+// } else {
+// const char *import_name = namespace_import->path ? buf_ptr(namespace_import->path) : "(C import)";
+// add_node_error(g, node,
+// buf_sprintf("no member named '%s' in '%s'", buf_ptr(field_name), import_name));
+// return g->builtin_types.entry_invalid;
+// }
+// } else {
+// add_node_error(g, node,
+// buf_sprintf("type '%s' does not support field access", buf_ptr(&struct_type->name)));
+// return g->builtin_types.entry_invalid;
+// }
+//}
+//
-bool ir_has_side_effects(IrInstruction *instruction) {
- switch (instruction->id) {
- case IrInstructionIdInvalid:
- zig_unreachable();
- case IrInstructionIdBr:
- case IrInstructionIdCondBr:
- case IrInstructionIdSwitchBr:
- case IrInstructionIdDeclVar:
- case IrInstructionIdStorePtr:
- case IrInstructionIdCall:
- case IrInstructionIdReturn:
- case IrInstructionIdUnreachable:
- return true;
- case IrInstructionIdPhi:
- case IrInstructionIdUnOp:
- case IrInstructionIdBinOp:
- case IrInstructionIdLoadPtr:
- case IrInstructionIdConst:
- case IrInstructionIdCast:
- case IrInstructionIdContainerInitList:
- case IrInstructionIdContainerInitFields:
- case IrInstructionIdFieldPtr:
- case IrInstructionIdElemPtr:
- case IrInstructionIdVarPtr:
- case IrInstructionIdTypeOf:
- case IrInstructionIdToPtrType:
- case IrInstructionIdPtrTypeChild:
- case IrInstructionIdReadField:
- case IrInstructionIdStructFieldPtr:
- return false;
- case IrInstructionIdBuiltinCall:
- return ir_builtin_call_has_side_effects((IrInstructionBuiltinCall *)instruction);
- }
- zig_unreachable();
-}
+//static TypeTableEntry *analyze_lvalue(CodeGen *g, ImportTableEntry *import, BlockContext *block_context,
+// AstNode *lhs_node, LValPurpose purpose, bool is_ptr_const)
+//{
+// TypeTableEntry *expected_rhs_type = nullptr;
+// lhs_node->block_context = block_context;
+// if (lhs_node->type == NodeTypeSymbol) {
+// bool pointer_only = purpose == LValPurposeAddressOf;
+// expected_rhs_type = analyze_symbol_expr(g, import, block_context, nullptr, lhs_node, pointer_only);
+// if (expected_rhs_type->id == TypeTableEntryIdInvalid) {
+// return g->builtin_types.entry_invalid;
+// }
+// if (purpose != LValPurposeAddressOf) {
+// Buf *name = lhs_node->data.symbol_expr.symbol;
+// VariableTableEntry *var = find_variable(g, block_context, name);
+// if (var) {
+// if (var->src_is_const) {
+// add_node_error(g, lhs_node, buf_sprintf("cannot assign to constant"));
+// expected_rhs_type = g->builtin_types.entry_invalid;
+// } else {
+// expected_rhs_type = var->type;
+// get_resolved_expr(lhs_node)->variable = var;
+// }
+// } else {
+// add_node_error(g, lhs_node,
+// buf_sprintf("use of undeclared identifier '%s'", buf_ptr(name)));
+// expected_rhs_type = g->builtin_types.entry_invalid;
+// }
+// }
+// } else if (lhs_node->type == NodeTypeArrayAccessExpr) {
+// expected_rhs_type = analyze_array_access_expr(g, import, block_context, lhs_node, purpose);
+// } else if (lhs_node->type == NodeTypeFieldAccessExpr) {
+// expected_rhs_type = analyze_field_access_expr(g, import, block_context, nullptr, lhs_node);
+// } else if (lhs_node->type == NodeTypePrefixOpExpr &&
+// lhs_node->data.prefix_op_expr.prefix_op == PrefixOpDereference)
+// {
+// assert(purpose == LValPurposeAssign);
+// AstNode *target_node = lhs_node->data.prefix_op_expr.primary_expr;
+// TypeTableEntry *type_entry = analyze_expression(g, import, block_context, nullptr, target_node);
+// if (type_entry->id == TypeTableEntryIdInvalid) {
+// expected_rhs_type = type_entry;
+// } else if (type_entry->id == TypeTableEntryIdPointer) {
+// expected_rhs_type = type_entry->data.pointer.child_type;
+// } else {
+// add_node_error(g, target_node,
+// buf_sprintf("indirection requires pointer operand ('%s' invalid)",
+// buf_ptr(&type_entry->name)));
+// expected_rhs_type = g->builtin_types.entry_invalid;
+// }
+// } else {
+// if (purpose == LValPurposeAssign) {
+// add_node_error(g, lhs_node, buf_sprintf("invalid assignment target"));
+// expected_rhs_type = g->builtin_types.entry_invalid;
+// } else if (purpose == LValPurposeAddressOf) {
+// TypeTableEntry *type_entry = analyze_expression(g, import, block_context, nullptr, lhs_node);
+// if (type_entry->id == TypeTableEntryIdInvalid) {
+// expected_rhs_type = g->builtin_types.entry_invalid;
+// } else if (type_entry->id == TypeTableEntryIdMetaType) {
+// expected_rhs_type = type_entry;
+// } else {
+// add_node_error(g, lhs_node, buf_sprintf("invalid addressof target"));
+// expected_rhs_type = g->builtin_types.entry_invalid;
+// }
+// }
+// }
+// assert(expected_rhs_type);
+// return expected_rhs_type;
+//}
-IrInstruction *ir_exec_const_result(IrExecutable *exec) {
- if (exec->basic_block_list.length != 1)
- return nullptr;
- IrBasicBlock *bb = exec->basic_block_list.at(0);
- if (bb->instruction_list.length != 1)
- return nullptr;
- IrInstruction *only_inst = bb->instruction_list.at(0);
- if (only_inst->id != IrInstructionIdReturn)
- return nullptr;
+//static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
+// TypeTableEntry *expected_type, AstNode *node)
+//{
+// assert(node->type == NodeTypeBinOpExpr);
+// BinOpType bin_op_type = node->data.bin_op_expr.bin_op;
+// switch (bin_op_type) {
+// case BinOpTypeAssign:
+// case BinOpTypeAssignTimes:
+// case BinOpTypeAssignTimesWrap:
+// case BinOpTypeAssignDiv:
+// case BinOpTypeAssignMod:
+// case BinOpTypeAssignPlus:
+// case BinOpTypeAssignPlusWrap:
+// case BinOpTypeAssignMinus:
+// case BinOpTypeAssignMinusWrap:
+// case BinOpTypeAssignBitShiftLeft:
+// case BinOpTypeAssignBitShiftLeftWrap:
+// case BinOpTypeAssignBitShiftRight:
+// case BinOpTypeAssignBitAnd:
+// case BinOpTypeAssignBitXor:
+// case BinOpTypeAssignBitOr:
+// case BinOpTypeAssignBoolAnd:
+// case BinOpTypeAssignBoolOr:
+// {
+// AstNode *lhs_node = node->data.bin_op_expr.op1;
+//
+// TypeTableEntry *expected_rhs_type = analyze_lvalue(g, import, context, lhs_node,
+// LValPurposeAssign, false);
+// if (expected_rhs_type->id == TypeTableEntryIdInvalid) {
+// return g->builtin_types.entry_invalid;
+// } else if (!is_op_allowed(expected_rhs_type, node->data.bin_op_expr.bin_op)) {
+// if (expected_rhs_type->id != TypeTableEntryIdInvalid) {
+// add_node_error(g, lhs_node,
+// buf_sprintf("operator not allowed for type '%s'",
+// buf_ptr(&expected_rhs_type->name)));
+// }
+// }
+//
+// analyze_expression(g, import, context, expected_rhs_type, node->data.bin_op_expr.op2);
+// // not const ok because expression has side effects
+// return g->builtin_types.entry_void;
+// }
+// case BinOpTypeBoolOr:
+// case BinOpTypeBoolAnd:
+// return analyze_logic_bin_op_expr(g, import, context, node);
+// case BinOpTypeCmpEq:
+// case BinOpTypeCmpNotEq:
+// case BinOpTypeCmpLessThan:
+// case BinOpTypeCmpGreaterThan:
+// case BinOpTypeCmpLessOrEq:
+// case BinOpTypeCmpGreaterOrEq:
+// return analyze_bool_bin_op_expr(g, import, context, node);
+// case BinOpTypeBinOr:
+// case BinOpTypeBinXor:
+// case BinOpTypeBinAnd:
+// case BinOpTypeBitShiftLeft:
+// case BinOpTypeBitShiftLeftWrap:
+// case BinOpTypeBitShiftRight:
+// case BinOpTypeAdd:
+// case BinOpTypeAddWrap:
+// case BinOpTypeSub:
+// case BinOpTypeSubWrap:
+// case BinOpTypeMult:
+// case BinOpTypeMultWrap:
+// case BinOpTypeDiv:
+// case BinOpTypeMod:
+// {
+// AstNode **op1 = node->data.bin_op_expr.op1->parent_field;
+// AstNode **op2 = node->data.bin_op_expr.op2->parent_field;
+// TypeTableEntry *lhs_type = analyze_expression(g, import, context, nullptr, *op1);
+// TypeTableEntry *rhs_type = analyze_expression(g, import, context, nullptr, *op2);
+//
+// AstNode *op_nodes[] = {*op1, *op2};
+// TypeTableEntry *op_types[] = {lhs_type, rhs_type};
+//
+// TypeTableEntry *resolved_type = resolve_peer_type_compatibility(g, import, context, node,
+// op_nodes, op_types, 2);
+//
+// if (resolved_type->id == TypeTableEntryIdInvalid) {
+// return resolved_type;
+// }
+//
+// if (resolved_type->id == TypeTableEntryIdInt ||
+// resolved_type->id == TypeTableEntryIdNumLitInt)
+// {
+// // int
+// } else if ((resolved_type->id == TypeTableEntryIdFloat ||
+// resolved_type->id == TypeTableEntryIdNumLitFloat) &&
+// (bin_op_type == BinOpTypeAdd ||
+// bin_op_type == BinOpTypeSub ||
+// bin_op_type == BinOpTypeMult ||
+// bin_op_type == BinOpTypeDiv ||
+// bin_op_type == BinOpTypeMod))
+// {
+// // float
+// } else {
+// add_node_error(g, node, buf_sprintf("invalid operands to binary expression: '%s' and '%s'",
+// buf_ptr(&lhs_type->name), buf_ptr(&rhs_type->name)));
+// return g->builtin_types.entry_invalid;
+// }
+//
+// ConstExprValue *op1_val = &get_resolved_expr(*op1)->const_val;
+// ConstExprValue *op2_val = &get_resolved_expr(*op2)->const_val;
+// if (!op1_val->ok || !op2_val->ok) {
+// return resolved_type;
+// }
+//
+// ConstExprValue *out_val = &get_resolved_expr(node)->const_val;
+// int err;
+// if ((err = eval_const_expr_bin_op(op1_val, resolved_type, bin_op_type,
+// op2_val, resolved_type, out_val)))
+// {
+// if (err == ErrorDivByZero) {
+// add_node_error(g, node, buf_sprintf("division by zero is undefined"));
+// return g->builtin_types.entry_invalid;
+// } else if (err == ErrorOverflow) {
+// add_node_error(g, node, buf_sprintf("value cannot be represented in any integer type"));
+// return g->builtin_types.entry_invalid;
+// }
+// return g->builtin_types.entry_invalid;
+// }
+//
+// num_lit_fits_in_other_type(g, node, resolved_type);
+// return resolved_type;
+// }
+// case BinOpTypeUnwrapMaybe:
+// {
+// AstNode *op1 = node->data.bin_op_expr.op1;
+// AstNode *op2 = node->data.bin_op_expr.op2;
+// TypeTableEntry *lhs_type = analyze_expression(g, import, context, nullptr, op1);
+//
+// if (lhs_type->id == TypeTableEntryIdInvalid) {
+// return lhs_type;
+// } else if (lhs_type->id == TypeTableEntryIdMaybe) {
+// TypeTableEntry *child_type = lhs_type->data.maybe.child_type;
+// analyze_expression(g, import, context, child_type, op2);
+// return child_type;
+// } else {
+// add_node_error(g, op1,
+// buf_sprintf("expected maybe type, got '%s'",
+// buf_ptr(&lhs_type->name)));
+// return g->builtin_types.entry_invalid;
+// }
+// }
+// case BinOpTypeArrayCat:
+// {
+// AstNode **op1 = node->data.bin_op_expr.op1->parent_field;
+// AstNode **op2 = node->data.bin_op_expr.op2->parent_field;
+//
+// TypeTableEntry *op1_type = analyze_expression(g, import, context, nullptr, *op1);
+// TypeTableEntry *child_type;
+// if (op1_type->id == TypeTableEntryIdInvalid) {
+// return g->builtin_types.entry_invalid;
+// } else if (op1_type->id == TypeTableEntryIdArray) {
+// child_type = op1_type->data.array.child_type;
+// } else if (op1_type->id == TypeTableEntryIdPointer &&
+// op1_type->data.pointer.child_type == g->builtin_types.entry_u8) {
+// child_type = op1_type->data.pointer.child_type;
+// } else {
+// add_node_error(g, *op1, buf_sprintf("expected array or C string literal, got '%s'",
+// buf_ptr(&op1_type->name)));
+// return g->builtin_types.entry_invalid;
+// }
+//
+// TypeTableEntry *op2_type = analyze_expression(g, import, context, nullptr, *op2);
+//
+// if (op2_type->id == TypeTableEntryIdInvalid) {
+// return g->builtin_types.entry_invalid;
+// } else if (op2_type->id == TypeTableEntryIdArray) {
+// if (op2_type->data.array.child_type != child_type) {
+// add_node_error(g, *op2, buf_sprintf("expected array of type '%s', got '%s'",
+// buf_ptr(&child_type->name),
+// buf_ptr(&op2_type->name)));
+// return g->builtin_types.entry_invalid;
+// }
+// } else if (op2_type->id == TypeTableEntryIdPointer &&
+// op2_type->data.pointer.child_type == g->builtin_types.entry_u8) {
+// } else {
+// add_node_error(g, *op2, buf_sprintf("expected array or C string literal, got '%s'",
+// buf_ptr(&op2_type->name)));
+// return g->builtin_types.entry_invalid;
+// }
+//
+// ConstExprValue *op1_val = &get_resolved_expr(*op1)->const_val;
+// ConstExprValue *op2_val = &get_resolved_expr(*op2)->const_val;
+//
+// AstNode *bad_node;
+// if (!op1_val->ok) {
+// bad_node = *op1;
+// } else if (!op2_val->ok) {
+// bad_node = *op2;
+// } else {
+// bad_node = nullptr;
+// }
+// if (bad_node) {
+// add_node_error(g, bad_node, buf_sprintf("array concatenation requires constant expression"));
+// return g->builtin_types.entry_invalid;
+// }
+//
+// ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
+// const_val->ok = true;
+// const_val->depends_on_compile_var = op1_val->depends_on_compile_var ||
+// op2_val->depends_on_compile_var;
+//
+// if (op1_type->id == TypeTableEntryIdArray) {
+// uint64_t new_len = op1_type->data.array.len + op2_type->data.array.len;
+// const_val->data.x_array.fields = allocate<ConstExprValue*>(new_len);
+// uint64_t next_index = 0;
+// for (uint64_t i = 0; i < op1_type->data.array.len; i += 1, next_index += 1) {
+// const_val->data.x_array.fields[next_index] = op1_val->data.x_array.fields[i];
+// }
+// for (uint64_t i = 0; i < op2_type->data.array.len; i += 1, next_index += 1) {
+// const_val->data.x_array.fields[next_index] = op2_val->data.x_array.fields[i];
+// }
+// return get_array_type(g, child_type, new_len);
+// } else if (op1_type->id == TypeTableEntryIdPointer) {
+// if (!op1_val->data.x_ptr.is_c_str) {
+// add_node_error(g, *op1,
+// buf_sprintf("expected array or C string literal, got '%s'",
+// buf_ptr(&op1_type->name)));
+// return g->builtin_types.entry_invalid;
+// } else if (!op2_val->data.x_ptr.is_c_str) {
+// add_node_error(g, *op2,
+// buf_sprintf("expected array or C string literal, got '%s'",
+// buf_ptr(&op2_type->name)));
+// return g->builtin_types.entry_invalid;
+// }
+// const_val->data.x_ptr.is_c_str = true;
+// const_val->data.x_ptr.len = op1_val->data.x_ptr.len + op2_val->data.x_ptr.len - 1;
+// const_val->data.x_ptr.ptr = allocate<ConstExprValue*>(const_val->data.x_ptr.len);
+// uint64_t next_index = 0;
+// for (uint64_t i = 0; i < op1_val->data.x_ptr.len - 1; i += 1, next_index += 1) {
+// const_val->data.x_ptr.ptr[next_index] = op1_val->data.x_ptr.ptr[i];
+// }
+// for (uint64_t i = 0; i < op2_val->data.x_ptr.len; i += 1, next_index += 1) {
+// const_val->data.x_ptr.ptr[next_index] = op2_val->data.x_ptr.ptr[i];
+// }
+// return op1_type;
+// } else {
+// zig_unreachable();
+// }
+// }
+// case BinOpTypeArrayMult:
+// return analyze_array_mult(g, import, context, expected_type, node);
+// case BinOpTypeInvalid:
+// zig_unreachable();
+// }
+// zig_unreachable();
+//}
- IrInstructionReturn *ret_inst = (IrInstructionReturn *)only_inst;
- IrInstruction *value = ret_inst->value;
- assert(value->static_value.ok);
- return value;
-}
+
+//static TypeTableEntry *analyze_bool_bin_op_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
+// AstNode *node)
+//{
+// assert(node->type == NodeTypeBinOpExpr);
+// BinOpType bin_op_type = node->data.bin_op_expr.bin_op;
+//
+// AstNode **op1 = &node->data.bin_op_expr.op1;
+// AstNode **op2 = &node->data.bin_op_expr.op2;
+// TypeTableEntry *op1_type = analyze_expression(g, import, context, nullptr, *op1);
+// TypeTableEntry *op2_type = analyze_expression(g, import, context, nullptr, *op2);
+//
+// AstNode *op_nodes[] = {*op1, *op2};
+// TypeTableEntry *op_types[] = {op1_type, op2_type};
+//
+// TypeTableEntry *resolved_type = resolve_peer_type_compatibility(g, import, context, node,
+// op_nodes, op_types, 2);
+//
+// bool is_equality_cmp = (bin_op_type == BinOpTypeCmpEq || bin_op_type == BinOpTypeCmpNotEq);
+//
+// switch (resolved_type->id) {
+// case TypeTableEntryIdInvalid:
+// return g->builtin_types.entry_invalid;
+//
+// case TypeTableEntryIdNumLitFloat:
+// case TypeTableEntryIdNumLitInt:
+// case TypeTableEntryIdInt:
+// case TypeTableEntryIdFloat:
+// break;
+//
+// case TypeTableEntryIdBool:
+// case TypeTableEntryIdMetaType:
+// case TypeTableEntryIdVoid:
+// case TypeTableEntryIdPointer:
+// case TypeTableEntryIdPureError:
+// case TypeTableEntryIdFn:
+// case TypeTableEntryIdTypeDecl:
+// case TypeTableEntryIdNamespace:
+// case TypeTableEntryIdBlock:
+// case TypeTableEntryIdGenericFn:
+// if (!is_equality_cmp) {
+// add_node_error(g, node,
+// buf_sprintf("operator not allowed for type '%s'", buf_ptr(&resolved_type->name)));
+// return g->builtin_types.entry_invalid;
+// }
+// break;
+//
+// case TypeTableEntryIdEnum:
+// if (!is_equality_cmp || resolved_type->data.enumeration.gen_field_count != 0) {
+// add_node_error(g, node,
+// buf_sprintf("operator not allowed for type '%s'", buf_ptr(&resolved_type->name)));
+// return g->builtin_types.entry_invalid;
+// }
+// break;
+//
+// case TypeTableEntryIdUnreachable:
+// case TypeTableEntryIdArray:
+// case TypeTableEntryIdStruct:
+// case TypeTableEntryIdUndefLit:
+// case TypeTableEntryIdNullLit:
+// case TypeTableEntryIdMaybe:
+// case TypeTableEntryIdErrorUnion:
+// case TypeTableEntryIdUnion:
+// add_node_error(g, node,
+// buf_sprintf("operator not allowed for type '%s'", buf_ptr(&resolved_type->name)));
+// return g->builtin_types.entry_invalid;
+//
+// case TypeTableEntryIdVar:
+// zig_unreachable();
+// }
+//
+// ConstExprValue *op1_val = &get_resolved_expr(*op1)->const_val;
+// ConstExprValue *op2_val = &get_resolved_expr(*op2)->const_val;
+// if (!op1_val->ok || !op2_val->ok) {
+// return g->builtin_types.entry_bool;
+// }
+//
+//
+// ConstExprValue *out_val = &get_resolved_expr(node)->const_val;
+// eval_const_expr_bin_op(op1_val, op1_type, bin_op_type, op2_val, op2_type, out_val);
+// return g->builtin_types.entry_bool;
+//
+//}
+//
+////
+//static TypeTableEntry *analyze_if(CodeGen *g, ImportTableEntry *import, BlockContext *parent_context,
+// TypeTableEntry *expected_type, AstNode *node,
+// AstNode **then_node, AstNode **else_node, bool cond_is_const, bool cond_bool_val)
+//{
+// if (!*else_node) {
+// *else_node = create_ast_void_node(g, import, node);
+// normalize_parent_ptrs(node);
+// }
+//
+// BlockContext *then_context;
+// BlockContext *else_context;
+// if (cond_is_const) {
+// if (cond_bool_val) {
+// then_context = parent_context;
+// else_context = new_block_context(node, parent_context);
+//
+// else_context->codegen_excluded = true;
+// } else {
+// then_context = new_block_context(node, parent_context);
+// else_context = parent_context;
+//
+// then_context->codegen_excluded = true;
+// }
+// } else {
+// then_context = parent_context;
+// else_context = parent_context;
+// }
+//
+// TypeTableEntry *then_type = nullptr;
+// TypeTableEntry *else_type = nullptr;
+//
+// if (!then_context->codegen_excluded) {
+// then_type = analyze_expression(g, import, then_context, expected_type, *then_node);
+// if (then_type->id == TypeTableEntryIdInvalid) {
+// return g->builtin_types.entry_invalid;
+// }
+// }
+// if (!else_context->codegen_excluded) {
+// else_type = analyze_expression(g, import, else_context, expected_type, *else_node);
+// if (else_type->id == TypeTableEntryIdInvalid) {
+// return g->builtin_types.entry_invalid;
+// }
+// }
+//
+// TypeTableEntry *result_type;
+// if (then_context->codegen_excluded) {
+// result_type = else_type;
+// } else if (else_context->codegen_excluded) {
+// result_type = then_type;
+// } else if (expected_type) {
+// result_type = (then_type->id == TypeTableEntryIdUnreachable) ? else_type : then_type;
+// } else {
+// AstNode *op_nodes[] = {*then_node, *else_node};
+// TypeTableEntry *op_types[] = {then_type, else_type};
+// result_type = resolve_peer_type_compatibility(g, import, parent_context, node, op_nodes, op_types, 2);
+// }
+//
+// if (!cond_is_const) {
+// return add_error_if_type_is_num_lit(g, result_type, node);
+// }
+//
+// ConstExprValue *other_const_val;
+// if (cond_bool_val) {
+// other_const_val = &get_resolved_expr(*then_node)->const_val;
+// } else {
+// other_const_val = &get_resolved_expr(*else_node)->const_val;
+// }
+// if (!other_const_val->ok) {
+// return add_error_if_type_is_num_lit(g, result_type, node);
+// }
+//
+// ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
+// *const_val = *other_const_val;
+// // the condition depends on a compile var, so the entire if statement does too
+// const_val->depends_on_compile_var = true;
+// return result_type;
+//}
+//
+//static TypeTableEntry *analyze_if_var_expr(CodeGen *g, ImportTableEntry *import, BlockContext *parent_context,
+// TypeTableEntry *expected_type, AstNode *node)
+//{
+// assert(node->type == NodeTypeIfVarExpr);
+//
+// BlockContext *child_context = new_block_context(node, parent_context);
+//
+// analyze_variable_declaration_raw(g, import, child_context, node, &node->data.if_var_expr.var_decl, true,
+// nullptr, node->data.if_var_expr.var_is_ptr);
+// VariableTableEntry *var = node->data.if_var_expr.var_decl.variable;
+// if (var->type->id == TypeTableEntryIdInvalid) {
+// return g->builtin_types.entry_invalid;
+// }
+// AstNode *var_expr_node = node->data.if_var_expr.var_decl.expr;
+// ConstExprValue *var_const_val = &get_resolved_expr(var_expr_node)->const_val;
+// bool cond_is_const = var_const_val->ok;
+// bool cond_bool_val = cond_is_const ? (var_const_val->data.x_maybe != nullptr) : false;
+//
+//
+// AstNode **then_node = &node->data.if_var_expr.then_block;
+// AstNode **else_node = &node->data.if_var_expr.else_node;
+//
+// return analyze_if(g, import, child_context, expected_type,
+// node, then_node, else_node, cond_is_const, cond_bool_val);
+//}
+//
+//static TypeTableEntry *bad_method_call(CodeGen *g, AstNode *node, TypeTableEntry *container_type,
+// TypeTableEntry *expected_param_type, FnTableEntry *fn_table_entry)
+//{
+// ErrorMsg *msg = add_node_error(g, node,
+// buf_sprintf("function called as method of '%s', but first parameter is of type '%s'",
+// buf_ptr(&container_type->name),
+// buf_ptr(&expected_param_type->name)));
+// if (fn_table_entry) {
+// add_error_note(g, msg, fn_table_entry->proto_node, buf_sprintf("function declared here"));
+// }
+// return g->builtin_types.entry_invalid;
+//}
+//
+//// 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)
+//{
+// assert(node->type == NodeTypeFnCallExpr);
+//
+// if (fn_type->id == TypeTableEntryIdInvalid) {
+// return fn_type;
+// }
+//
+// // 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;
+//
+// // count parameters
+// size_t struct_node_1_or_0 = struct_node ? 1 : 0;
+// size_t 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);
+// size_t call_param_count = node->data.fn_call_expr.params.length;
+// size_t expect_arg_count = src_param_count - struct_node_1_or_0;
+//
+// bool ok_invocation = true;
+//
+// if (fn_type->data.fn.fn_type_id.is_var_args) {
+// if (call_param_count < expect_arg_count) {
+// ok_invocation = false;
+// add_node_error(g, node,
+// buf_sprintf("expected at least %zu arguments, got %zu", src_param_count, call_param_count));
+// }
+// } else if (expect_arg_count != call_param_count) {
+// ok_invocation = false;
+// add_node_error(g, node,
+// buf_sprintf("expected %zu arguments, got %zu", expect_arg_count, call_param_count));
+// }
+//
+// bool all_args_const_expr = true;
+//
+// if (struct_node) {
+// Expr *struct_expr = get_resolved_expr(struct_node);
+// ConstExprValue *struct_const_val = &struct_expr->const_val;
+// if (!struct_const_val->ok) {
+// all_args_const_expr = false;
+// }
+//
+// FnTypeParamInfo *param_info = &fn_type->data.fn.fn_type_id.param_info[0];
+// TypeTableEntry *expected_param_type = param_info->type;
+// TypeTableEntry *container_bare_type = container_ref_type(struct_expr->type_entry);
+// if (is_container_ref(expected_param_type)) {
+// TypeTableEntry *param_bare_type = container_ref_type(expected_param_type);
+// if (param_bare_type != container_bare_type) {
+// return bad_method_call(g, node, container_bare_type, expected_param_type, fn_table_entry);
+// }
+// } else {
+// return bad_method_call(g, node, container_bare_type, expected_param_type, fn_table_entry);
+// }
+// }
+//
+// // 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.
+// size_t next_type_i = struct_node_1_or_0;
+// for (size_t call_i = 0; call_i < call_param_count; call_i += 1) {
+// size_t 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;
+// 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;
+// }
+//
+// ConstExprValue *const_arg_val = &get_resolved_expr(*param_node)->const_val;
+// if (!const_arg_val->ok) {
+// all_args_const_expr = false;
+// }
+// }
+//
+// TypeTableEntry *return_type = fn_type->data.fn.fn_type_id.return_type;
+//
+// if (return_type->id == TypeTableEntryIdInvalid) {
+// return return_type;
+// }
+//
+// 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) {
+// analyze_fn_body(g, fn_table_entry);
+// if (fn_table_entry->proto_node->data.fn_proto.skip) {
+// return g->builtin_types.entry_invalid;
+// }
+// }
+// if (all_args_const_expr) {
+// if (fn_table_entry->is_pure && fn_table_entry->anal_state == FnAnalStateComplete) {
+// if (eval_fn(g, node, fn_table_entry, result_val, 1000, struct_node)) {
+// // function evaluation generated an error
+// return g->builtin_types.entry_invalid;
+// }
+// return return_type;
+// }
+// }
+// }
+// if (!ok_invocation || !fn_table_entry || !fn_table_entry->is_pure || fn_table_entry->want_pure == WantPureFalse) {
+// // calling an impure fn is impure
+// mark_impure_fn(g, context, node);
+// if (fn_table_entry && fn_table_entry->want_pure == WantPureTrue) {
+// return g->builtin_types.entry_invalid;
+// }
+// }
+//
+// // TODO
+// //if (handle_is_ptr(return_type)) {
+// // if (context->fn_entry) {
+// // context->fn_entry->cast_alloca_list.append(node);
+// // } else if (!result_val->ok) {
+// // add_node_error(g, node, buf_sprintf("unable to evaluate constant expression"));
+// // }
+// //}
+//
+// return return_type;
+//}
+//
+//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(call_node->type == NodeTypeFnCallExpr);
+// assert(fn_table_entry);
+//
+// AstNode *decl_node = fn_table_entry->proto_node;
+//
+// // count parameters
+// size_t struct_node_1_or_0 = (struct_node ? 1 : 0);
+// size_t src_param_count = decl_node->data.fn_proto.params.length;
+// size_t 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 %zu arguments, got %zu", src_param_count - struct_node_1_or_0, call_param_count));
+// return g->builtin_types.entry_invalid;
+// }
+//
+// size_t inline_or_var_type_arg_count = decl_node->data.fn_proto.inline_or_var_type_arg_count;
+// assert(inline_or_var_type_arg_count > 0);
+//
+// BlockContext *child_context = decl_node->owner->block_context;
+// size_t 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_or_var_type_arg_count;
+// generic_fn_type_id->generic_params = allocate<GenericParamValue>(inline_or_var_type_arg_count);
+//
+// size_t next_impl_i = 0;
+// for (size_t call_i = 0; call_i < call_param_count; call_i += 1) {
+// size_t 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);
+//
+// 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;
+// }
+//
+// bool is_var_type = (expected_param_type->id == TypeTableEntryIdVar);
+// bool is_inline = generic_param_decl_node->data.param_decl.is_inline;
+// if (!is_inline && !is_var_type) {
+// next_impl_i += 1;
+// continue;
+// }
+//
+//
+// AstNode **param_node = &call_node->data.fn_call_expr.params.at(call_i);
+// TypeTableEntry *param_type = analyze_expression(g, import, parent_context,
+// is_var_type ? nullptr : 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 (is_inline && !const_val->ok) {
+// add_node_error(g, *param_node,
+// buf_sprintf("unable to evaluate constant expression for inline parameter"));
+//
+// return g->builtin_types.entry_invalid;
+// }
+//
+// VariableTableEntry *var = add_local_var_shadowable(g, generic_param_decl_node, decl_node->owner, child_context,
+// generic_param_decl_node->data.param_decl.name, param_type, true, *param_node, true);
+// // This generic function instance could be called with anything, so when this variable is read it
+// // needs to know that it depends on compile time variable data.
+// var->force_depends_on_compile_var = true;
+//
+// GenericParamValue *generic_param_value =
+// &generic_fn_type_id->generic_params[next_generic_param_index];
+// generic_param_value->type = param_type;
+// generic_param_value->node = is_inline ? *param_node : nullptr;
+// generic_param_value->impl_index = next_impl_i;
+// next_generic_param_index += 1;
+//
+// if (!is_inline) {
+// next_impl_i += 1;
+// }
+// }
+//
+// assert(next_generic_param_index == inline_or_var_type_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.inline_or_var_type_arg_count = 0;
+// impl_decl_node->data.fn_proto.generic_proto_node = decl_node;
+//
+// // replace var arg types with actual types
+// for (size_t generic_arg_i = 0; generic_arg_i < inline_or_var_type_arg_count; generic_arg_i += 1) {
+// GenericParamValue *generic_param_value = &generic_fn_type_id->generic_params[generic_arg_i];
+// if (!generic_param_value->node) {
+// size_t impl_i = generic_param_value->impl_index;
+// AstNode *impl_param_decl_node = impl_decl_node->data.fn_proto.params.at(impl_i);
+// assert(impl_param_decl_node->type == NodeTypeParamDecl);
+//
+// impl_param_decl_node->data.param_decl.type = create_ast_type_node(g, import,
+// generic_param_value->type, impl_param_decl_node);
+// normalize_parent_ptrs(impl_param_decl_node);
+// }
+// }
+//
+// 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;
+// }
+//
+// 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,
+// TypeTableEntry *expected_type, AstNode *node, TypeTableEntry *generic_fn_type)
+//{
+// assert(node->type == NodeTypeFnCallExpr);
+// assert(generic_fn_type->id == TypeTableEntryIdGenericFn);
+//
+// AstNode *decl_node = generic_fn_type->data.generic_fn.decl_node;
+// assert(decl_node->type == NodeTypeContainerDecl);
+// ZigList<AstNode *> *generic_params = &decl_node->data.struct_decl.generic_params;
+//
+// size_t expected_param_count = generic_params->length;
+// size_t actual_param_count = node->data.fn_call_expr.params.length;
+//
+// if (actual_param_count != expected_param_count) {
+// add_node_error(g, first_executing_node(node),
+// buf_sprintf("expected %zu arguments, got %zu", expected_param_count, actual_param_count));
+// return g->builtin_types.entry_invalid;
+// }
+//
+// GenericFnTypeId *generic_fn_type_id = allocate<GenericFnTypeId>(1);
+// generic_fn_type_id->decl_node = decl_node;
+// generic_fn_type_id->generic_param_count = actual_param_count;
+// generic_fn_type_id->generic_params = allocate<GenericParamValue>(actual_param_count);
+//
+// BlockContext *child_context = decl_node->owner->block_context;
+// for (size_t i = 0; i < actual_param_count; i += 1) {
+// AstNode *generic_param_decl_node = generic_params->at(i);
+// assert(generic_param_decl_node->type == NodeTypeParamDecl);
+//
+// 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 = &node->data.fn_call_expr.params.at(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) {
+// VariableTableEntry *var = 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);
+// var->force_depends_on_compile_var = true;
+// } else {
+// add_node_error(g, *param_node, buf_sprintf("unable to evaluate constant expression"));
+//
+// return g->builtin_types.entry_invalid;
+// }
+//
+// GenericParamValue *generic_param_value = &generic_fn_type_id->generic_params[i];
+// generic_param_value->type = param_type;
+// generic_param_value->node = *param_node;
+// }
+//
+// auto entry = g->generic_table.maybe_get(generic_fn_type_id);
+// if (entry) {
+// AstNode *impl_decl_node = entry->value;
+// assert(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);
+// }
+//
+// // 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,
+// TypeTableEntry *expected_type, AstNode *node)
+//{
+// AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr;
+//
+// if (node->data.fn_call_expr.is_builtin) {
+// zig_panic("moved builtin fn call code to ir.cpp");
+// }
+//
+// TypeTableEntry *invoke_type_entry = analyze_expression(g, import, context, nullptr, fn_ref_expr);
+// if (invoke_type_entry->id == TypeTableEntryIdInvalid) {
+// return g->builtin_types.entry_invalid;
+// }
+//
+// // use constant expression evaluator to figure out the function at compile time.
+// // otherwise we treat this as a function pointer.
+// ConstExprValue *const_val = &get_resolved_expr(fn_ref_expr)->const_val;
+//
+// if (const_val->ok) {
+// if (invoke_type_entry->id == TypeTableEntryIdMetaType) {
+// zig_unreachable();
+// } else if (invoke_type_entry->id == TypeTableEntryIdFn) {
+// 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 = 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) {
+// 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)));
+// return g->builtin_types.entry_invalid;
+// }
+// }
+//
+// // function pointer
+// if (invoke_type_entry->id == TypeTableEntryIdFn) {
+// return analyze_fn_call_ptr(g, import, context, expected_type, node, invoke_type_entry, nullptr);
+// } else {
+// add_node_error(g, fn_ref_expr,
+// buf_sprintf("type '%s' not a function", buf_ptr(&invoke_type_entry->name)));
+// return g->builtin_types.entry_invalid;
+// }
+//}
+//static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
+// TypeTableEntry *expected_type, AstNode *node)
+//{
+// AstNode **expr_node = &node->data.switch_expr.expr;
+// TypeTableEntry *expr_type = analyze_expression(g, import, context, nullptr, *expr_node);
+// ConstExprValue *expr_val = &get_resolved_expr(*expr_node)->const_val;
+// if (expr_val->ok && !expr_val->depends_on_compile_var) {
+// add_node_error(g, first_executing_node(*expr_node),
+// buf_sprintf("value is constant; unnecessary switch statement"));
+// }
+// ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
+//
+//
+// size_t prong_count = node->data.switch_expr.prongs.length;
+// AstNode **peer_nodes = allocate<AstNode*>(prong_count);
+// TypeTableEntry **peer_types = allocate<TypeTableEntry*>(prong_count);
+//
+// bool any_errors = false;
+// if (expr_type->id == TypeTableEntryIdInvalid) {
+// return expr_type;
+// } else if (expr_type->id == TypeTableEntryIdUnreachable) {
+// add_node_error(g, first_executing_node(*expr_node),
+// buf_sprintf("switch on unreachable expression not allowed"));
+// return g->builtin_types.entry_invalid;
+// }
+//
+//
+// size_t *field_use_counts = nullptr;
+// HashMap<int, AstNode *, int_hash, int_eq> err_use_nodes = {};
+// if (expr_type->id == TypeTableEntryIdEnum) {
+// field_use_counts = allocate<size_t>(expr_type->data.enumeration.src_field_count);
+// } else if (expr_type->id == TypeTableEntryIdErrorUnion) {
+// err_use_nodes.init(10);
+// }
+//
+// size_t *const_chosen_prong_index = &node->data.switch_expr.const_chosen_prong_index;
+// *const_chosen_prong_index = SIZE_MAX;
+// AstNode *else_prong = nullptr;
+// for (size_t prong_i = 0; prong_i < prong_count; prong_i += 1) {
+// AstNode *prong_node = node->data.switch_expr.prongs.at(prong_i);
+//
+// TypeTableEntry *var_type;
+// bool var_is_target_expr;
+// if (prong_node->data.switch_prong.items.length == 0) {
+// if (else_prong) {
+// add_node_error(g, prong_node, buf_sprintf("multiple else prongs in switch expression"));
+// any_errors = true;
+// } else {
+// else_prong = prong_node;
+// }
+// var_type = expr_type;
+// var_is_target_expr = true;
+// if (*const_chosen_prong_index == SIZE_MAX && expr_val->ok) {
+// *const_chosen_prong_index = prong_i;
+// }
+// } else {
+// bool all_agree_on_var_type = true;
+// var_type = nullptr;
+//
+// for (size_t item_i = 0; item_i < prong_node->data.switch_prong.items.length; item_i += 1) {
+// AstNode *item_node = prong_node->data.switch_prong.items.at(item_i);
+// if (item_node->type == NodeTypeSwitchRange) {
+// zig_panic("TODO range in switch statement");
+// }
+//
+// if (expr_type->id == TypeTableEntryIdEnum) {
+// if (item_node->type == NodeTypeSymbol) {
+// Buf *field_name = item_node->data.symbol_expr.symbol;
+// TypeEnumField *type_enum_field = find_enum_type_field(expr_type, field_name);
+// if (type_enum_field) {
+// item_node->data.symbol_expr.enum_field = type_enum_field;
+// if (!var_type) {
+// var_type = type_enum_field->type_entry;
+// }
+// if (type_enum_field->type_entry != var_type) {
+// all_agree_on_var_type = false;
+// }
+// uint32_t field_index = type_enum_field->value;
+// assert(field_use_counts);
+// field_use_counts[field_index] += 1;
+// if (field_use_counts[field_index] > 1) {
+// add_node_error(g, item_node,
+// buf_sprintf("duplicate switch value: '%s'",
+// buf_ptr(type_enum_field->name)));
+// any_errors = true;
+// }
+// if (!any_errors && expr_val->ok) {
+// if (expr_val->data.x_enum.tag == type_enum_field->value) {
+// *const_chosen_prong_index = prong_i;
+// }
+// }
+// } else {
+// add_node_error(g, item_node,
+// buf_sprintf("enum '%s' has no field '%s'",
+// buf_ptr(&expr_type->name), buf_ptr(field_name)));
+// any_errors = true;
+// }
+// } else {
+// add_node_error(g, item_node, buf_sprintf("expected enum tag name"));
+// any_errors = true;
+// }
+// } else if (expr_type->id == TypeTableEntryIdErrorUnion) {
+// if (item_node->type == NodeTypeSymbol) {
+// Buf *err_name = item_node->data.symbol_expr.symbol;
+// bool is_ok_case = buf_eql_str(err_name, "Ok");
+// auto err_table_entry = is_ok_case ? nullptr: g->error_table.maybe_get(err_name);
+// if (is_ok_case || err_table_entry) {
+// uint32_t err_value = is_ok_case ? 0 : err_table_entry->value->value;
+// item_node->data.symbol_expr.err_value = err_value;
+// TypeTableEntry *this_var_type;
+// if (is_ok_case) {
+// this_var_type = expr_type->data.error.child_type;
+// } else {
+// this_var_type = g->builtin_types.entry_pure_error;
+// }
+// if (!var_type) {
+// var_type = this_var_type;
+// }
+// if (this_var_type != var_type) {
+// all_agree_on_var_type = false;
+// }
+//
+// // detect duplicate switch values
+// auto existing_entry = err_use_nodes.maybe_get(err_value);
+// if (existing_entry) {
+// add_node_error(g, existing_entry->value,
+// buf_sprintf("duplicate switch value: '%s'", buf_ptr(err_name)));
+// any_errors = true;
+// } else {
+// err_use_nodes.put(err_value, item_node);
+// }
+//
+// if (!any_errors && expr_val->ok) {
+// if (expr_val->data.x_err.err->value == err_value) {
+// *const_chosen_prong_index = prong_i;
+// }
+// }
+// } else {
+// add_node_error(g, item_node,
+// buf_sprintf("use of undeclared error value '%s'", buf_ptr(err_name)));
+// any_errors = true;
+// }
+// } else {
+// add_node_error(g, item_node, buf_sprintf("expected error value name"));
+// any_errors = true;
+// }
+// } else {
+// if (!any_errors && expr_val->ok) {
+// // note: there is now a function in eval.cpp for doing const expr comparison
+// zig_panic("TODO determine if const exprs are equal");
+// }
+// TypeTableEntry *item_type = analyze_expression(g, import, context, expr_type, item_node);
+// if (item_type->id != TypeTableEntryIdInvalid) {
+// ConstExprValue *const_val = &get_resolved_expr(item_node)->const_val;
+// if (!const_val->ok) {
+// add_node_error(g, item_node,
+// buf_sprintf("unable to evaluate constant expression"));
+// any_errors = true;
+// }
+// }
+// }
+// }
+// if (!var_type || !all_agree_on_var_type) {
+// var_type = expr_type;
+// var_is_target_expr = true;
+// } else {
+// var_is_target_expr = false;
+// }
+// }
+//
+// BlockContext *child_context = new_block_context(node, context);
+// prong_node->data.switch_prong.block_context = child_context;
+// AstNode *var_node = prong_node->data.switch_prong.var_symbol;
+// if (var_node) {
+// assert(var_node->type == NodeTypeSymbol);
+// Buf *var_name = var_node->data.symbol_expr.symbol;
+// var_node->block_context = child_context;
+// prong_node->data.switch_prong.var = add_local_var(g, var_node, import,
+// child_context, var_name, var_type, true, nullptr);
+// prong_node->data.switch_prong.var_is_target_expr = var_is_target_expr;
+// }
+// }
+//
+// for (size_t prong_i = 0; prong_i < prong_count; prong_i += 1) {
+// AstNode *prong_node = node->data.switch_expr.prongs.at(prong_i);
+// BlockContext *child_context = prong_node->data.switch_prong.block_context;
+// child_context->codegen_excluded = expr_val->ok && (*const_chosen_prong_index != prong_i);
+//
+// if (child_context->codegen_excluded) {
+// peer_types[prong_i] = g->builtin_types.entry_unreachable;
+// } else {
+// peer_types[prong_i] = analyze_expression(g, import, child_context, expected_type,
+// prong_node->data.switch_prong.expr);
+// }
+// // This must go after the analyze_expression for
+// // prong_node->data.switch_prong.expr because of AST rewriting.
+// peer_nodes[prong_i] = prong_node->data.switch_prong.expr;
+// }
+//
+// if (expr_type->id == TypeTableEntryIdEnum && !else_prong) {
+// for (uint32_t i = 0; i < expr_type->data.enumeration.src_field_count; i += 1) {
+// if (field_use_counts[i] == 0) {
+// add_node_error(g, node,
+// buf_sprintf("enumeration value '%s' not handled in switch",
+// buf_ptr(expr_type->data.enumeration.fields[i].name)));
+// any_errors = true;
+// }
+// }
+// }
+//
+// if (any_errors) {
+// return g->builtin_types.entry_invalid;
+// }
+//
+// if (prong_count == 0) {
+// add_node_error(g, node, buf_sprintf("switch statement has no prongs"));
+// return g->builtin_types.entry_invalid;
+// }
+//
+// TypeTableEntry *result_type = resolve_peer_type_compatibility(g, import, context, node,
+// peer_nodes, peer_types, prong_count);
+//
+// if (expr_val->ok) {
+// assert(*const_chosen_prong_index != SIZE_MAX);
+//
+// *const_val = get_resolved_expr(peer_nodes[*const_chosen_prong_index])->const_val;
+// // the target expr depends on a compile var because we have an error on unnecessary
+// // switch statement, so the entire switch statement does too
+// const_val->depends_on_compile_var = true;
+//
+// if (!const_val->ok) {
+// return add_error_if_type_is_num_lit(g, result_type, node);
+// }
+// } else {
+// return add_error_if_type_is_num_lit(g, result_type, node);
+// }
+//
+// return result_type;
+//}
+//
+//static TypeTableEntry *analyze_return_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
+// TypeTableEntry *expected_type, AstNode *node)
+//{
+// if (!node->data.return_expr.expr) {
+// node->data.return_expr.expr = create_ast_void_node(g, import, node);
+// normalize_parent_ptrs(node);
+// }
+//
+// TypeTableEntry *expected_return_type = get_return_type(context);
+//
+// switch (node->data.return_expr.kind) {
+// case ReturnKindUnconditional:
+// zig_panic("TODO moved to ir.cpp");
+// case ReturnKindError:
+// {
+// TypeTableEntry *expected_err_type;
+// if (expected_type) {
+// expected_err_type = get_error_type(g, expected_type);
+// } else {
+// expected_err_type = nullptr;
+// }
+// TypeTableEntry *resolved_type = analyze_expression(g, import, context, expected_err_type,
+// node->data.return_expr.expr);
+// if (resolved_type->id == TypeTableEntryIdInvalid) {
+// return resolved_type;
+// } else if (resolved_type->id == TypeTableEntryIdErrorUnion) {
+// if (expected_return_type->id != TypeTableEntryIdErrorUnion &&
+// expected_return_type->id != TypeTableEntryIdPureError)
+// {
+// ErrorMsg *msg = add_node_error(g, node,
+// buf_sprintf("%%return statement in function with return type '%s'",
+// buf_ptr(&expected_return_type->name)));
+// AstNode *return_type_node = context->fn_entry->fn_def_node->data.fn_def.fn_proto->data.fn_proto.return_type;
+// add_error_note(g, msg, return_type_node, buf_sprintf("function return type here"));
+// }
+//
+// return resolved_type->data.error.child_type;
+// } else {
+// add_node_error(g, node->data.return_expr.expr,
+// buf_sprintf("expected error type, got '%s'", buf_ptr(&resolved_type->name)));
+// return g->builtin_types.entry_invalid;
+// }
+// }
+// case ReturnKindMaybe:
+// {
+// TypeTableEntry *expected_maybe_type;
+// if (expected_type) {
+// expected_maybe_type = get_maybe_type(g, expected_type);
+// } else {
+// expected_maybe_type = nullptr;
+// }
+// TypeTableEntry *resolved_type = analyze_expression(g, import, context, expected_maybe_type,
+// node->data.return_expr.expr);
+// if (resolved_type->id == TypeTableEntryIdInvalid) {
+// return resolved_type;
+// } else if (resolved_type->id == TypeTableEntryIdMaybe) {
+// if (expected_return_type->id != TypeTableEntryIdMaybe) {
+// ErrorMsg *msg = add_node_error(g, node,
+// buf_sprintf("?return statement in function with return type '%s'",
+// buf_ptr(&expected_return_type->name)));
+// AstNode *return_type_node = context->fn_entry->fn_def_node->data.fn_def.fn_proto->data.fn_proto.return_type;
+// add_error_note(g, msg, return_type_node, buf_sprintf("function return type here"));
+// }
+//
+// return resolved_type->data.maybe.child_type;
+// } else {
+// add_node_error(g, node->data.return_expr.expr,
+// buf_sprintf("expected maybe type, got '%s'", buf_ptr(&resolved_type->name)));
+// return g->builtin_types.entry_invalid;
+// }
+// }
+// }
+// zig_unreachable();
+//}
+//static TypeTableEntry *analyze_goto_pass1(CodeGen *g, ImportTableEntry *import, BlockContext *context,
+// TypeTableEntry *expected_type, AstNode *node)
+//{
+// assert(node->type == NodeTypeGoto);
+//
+// FnTableEntry *fn_table_entry = context->fn_entry;
+// assert(fn_table_entry);
+//
+// fn_table_entry->goto_list.append(node);
+//
+// return g->builtin_types.entry_unreachable;
+//}
+//
+//static TypeTableEntry *analyze_enum_value_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
+// AstNode *field_access_node, AstNode *value_node, TypeTableEntry *enum_type, Buf *field_name,
+// AstNode *out_node)
+//{
+// assert(field_access_node->type == NodeTypeFieldAccessExpr);
+//
+// TypeEnumField *type_enum_field = find_enum_type_field(enum_type, field_name);
+// if (type_enum_field->type_entry->id == TypeTableEntryIdInvalid) {
+// return g->builtin_types.entry_invalid;
+// }
+//
+// field_access_node->data.field_access_expr.type_enum_field = type_enum_field;
+//
+// if (type_enum_field) {
+// if (value_node) {
+// AstNode **value_node_ptr = value_node->parent_field;
+// TypeTableEntry *value_type = analyze_expression(g, import, context,
+// type_enum_field->type_entry, value_node);
+//
+// if (value_type->id == TypeTableEntryIdInvalid) {
+// return g->builtin_types.entry_invalid;
+// }
+//
+// StructValExprCodeGen *codegen = &field_access_node->data.field_access_expr.resolved_struct_val_expr;
+// codegen->type_entry = enum_type;
+// codegen->source_node = field_access_node;
+//
+// ConstExprValue *value_const_val = &get_resolved_expr(*value_node_ptr)->const_val;
+// if (value_const_val->ok) {
+// ConstExprValue *const_val = &get_resolved_expr(out_node)->const_val;
+// const_val->ok = true;
+// const_val->data.x_enum.tag = type_enum_field->value;
+// const_val->data.x_enum.payload = value_const_val;
+// } else {
+// if (context->fn_entry) {
+// context->fn_entry->struct_val_expr_alloca_list.append(codegen);
+// } else {
+// add_node_error(g, *value_node_ptr, buf_sprintf("unable to evaluate constant expression"));
+// return g->builtin_types.entry_invalid;
+// }
+// }
+// } else if (type_enum_field->type_entry->id != TypeTableEntryIdVoid) {
+// add_node_error(g, field_access_node,
+// buf_sprintf("enum value '%s.%s' requires parameter of type '%s'",
+// buf_ptr(&enum_type->name),
+// buf_ptr(field_name),
+// buf_ptr(&type_enum_field->type_entry->name)));
+// } else {
+// Expr *expr = get_resolved_expr(out_node);
+// expr->const_val.ok = true;
+// expr->const_val.data.x_enum.tag = type_enum_field->value;
+// expr->const_val.data.x_enum.payload = nullptr;
+// }
+// } else {
+// add_node_error(g, field_access_node,
+// buf_sprintf("no member named '%s' in '%s'", buf_ptr(field_name),
+// buf_ptr(&enum_type->name)));
+// }
+// return enum_type;
+//}
+//
+//static TypeTableEntry *analyze_container_member_access_inner(CodeGen *g,
+// TypeTableEntry *bare_struct_type, Buf *field_name, AstNode *node, TypeTableEntry *struct_type)
+//{
+// assert(node->type == NodeTypeFieldAccessExpr);
+// if (!is_slice(bare_struct_type)) {
+// BlockContext *container_block_context = get_container_block_context(bare_struct_type);
+// assert(container_block_context);
+// auto entry = container_block_context->decl_table.maybe_get(field_name);
+// AstNode *fn_decl_node = entry ? entry->value : nullptr;
+// if (fn_decl_node && fn_decl_node->type == NodeTypeFnProto) {
+// resolve_top_level_decl(g, fn_decl_node, false);
+// TopLevelDecl *tld = get_as_top_level_decl(fn_decl_node);
+// if (tld->resolution == TldResolutionInvalid) {
+// return g->builtin_types.entry_invalid;
+// }
+//
+// node->data.field_access_expr.is_member_fn = true;
+// FnTableEntry *fn_entry = fn_decl_node->data.fn_proto.fn_table_entry;
+// 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);
+// }
+// }
+// }
+// add_node_error(g, node,
+// buf_sprintf("no member named '%s' in '%s'", buf_ptr(field_name), buf_ptr(&bare_struct_type->name)));
+// return g->builtin_types.entry_invalid;
+//}
+//
+//static TypeTableEntry *analyze_container_member_access(CodeGen *g,
+// Buf *field_name, AstNode *node, TypeTableEntry *struct_type)
+//{
+// TypeTableEntry *bare_type = container_ref_type(struct_type);
+// if (!type_is_complete(bare_type)) {
+// resolve_container_type(g, bare_type);
+// }
+//
+// node->data.field_access_expr.bare_container_type = bare_type;
+//
+// if (bare_type->id == TypeTableEntryIdStruct) {
+// node->data.field_access_expr.type_struct_field = find_struct_type_field(bare_type, field_name);
+// if (node->data.field_access_expr.type_struct_field) {
+// return node->data.field_access_expr.type_struct_field->type_entry;
+// } else {
+// return analyze_container_member_access_inner(g, bare_type, field_name,
+// node, struct_type);
+// }
+// } else if (bare_type->id == TypeTableEntryIdEnum) {
+// node->data.field_access_expr.type_enum_field = find_enum_type_field(bare_type, field_name);
+// if (node->data.field_access_expr.type_enum_field) {
+// return node->data.field_access_expr.type_enum_field->type_entry;
+// } else {
+// return analyze_container_member_access_inner(g, bare_type, field_name,
+// node, struct_type);
+// }
+// } else if (bare_type->id == TypeTableEntryIdUnion) {
+// zig_panic("TODO");
+// } else {
+// zig_unreachable();
+// }
+//}
+//
+//static TypeTableEntry *analyze_slice_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
+// AstNode *node)
+//{
+// assert(node->type == NodeTypeSliceExpr);
+//
+// TypeTableEntry *array_type = analyze_expression(g, import, context, nullptr,
+// node->data.slice_expr.array_ref_expr);
+//
+// TypeTableEntry *return_type;
+//
+// if (array_type->id == TypeTableEntryIdInvalid) {
+// return_type = g->builtin_types.entry_invalid;
+// } else if (array_type->id == TypeTableEntryIdArray) {
+// return_type = get_slice_type(g, array_type->data.array.child_type,
+// node->data.slice_expr.is_const);
+// } else if (array_type->id == TypeTableEntryIdPointer) {
+// return_type = get_slice_type(g, array_type->data.pointer.child_type,
+// node->data.slice_expr.is_const);
+// } else if (array_type->id == TypeTableEntryIdStruct &&
+// array_type->data.structure.is_slice)
+// {
+// return_type = get_slice_type(g,
+// array_type->data.structure.fields[0].type_entry->data.pointer.child_type,
+// node->data.slice_expr.is_const);
+// } else {
+// add_node_error(g, node,
+// buf_sprintf("slice of non-array type '%s'", buf_ptr(&array_type->name)));
+// return_type = g->builtin_types.entry_invalid;
+// }
+//
+// if (return_type->id != TypeTableEntryIdInvalid) {
+// node->data.slice_expr.resolved_struct_val_expr.type_entry = return_type;
+// node->data.slice_expr.resolved_struct_val_expr.source_node = node;
+// context->fn_entry->struct_val_expr_alloca_list.append(&node->data.slice_expr.resolved_struct_val_expr);
+// }
+//
+// analyze_expression(g, import, context, g->builtin_types.entry_usize, node->data.slice_expr.start);
+//
+// if (node->data.slice_expr.end) {
+// analyze_expression(g, import, context, g->builtin_types.entry_usize, node->data.slice_expr.end);
+// }
+//
+// return return_type;
+//}
+//
+//static TypeTableEntry *analyze_array_access_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
+// AstNode *node, LValPurpose purpose)
+//{
+// TypeTableEntry *array_type = analyze_expression(g, import, context, nullptr,
+// node->data.array_access_expr.array_ref_expr);
+//
+// TypeTableEntry *return_type;
+//
+// if (array_type->id == TypeTableEntryIdInvalid) {
+// return_type = g->builtin_types.entry_invalid;
+// } else if (array_type->id == TypeTableEntryIdArray) {
+// if (array_type->data.array.len == 0) {
+// add_node_error(g, node, buf_sprintf("out of bounds array access"));
+// }
+// return_type = array_type->data.array.child_type;
+// } else if (array_type->id == TypeTableEntryIdPointer) {
+// if (array_type->data.pointer.is_const && purpose == LValPurposeAssign) {
+// add_node_error(g, node, buf_sprintf("cannot assign to constant"));
+// return g->builtin_types.entry_invalid;
+// }
+// return_type = array_type->data.pointer.child_type;
+// } else if (array_type->id == TypeTableEntryIdStruct &&
+// array_type->data.structure.is_slice)
+// {
+// TypeTableEntry *pointer_type = array_type->data.structure.fields[0].type_entry;
+// if (pointer_type->data.pointer.is_const && purpose == LValPurposeAssign) {
+// add_node_error(g, node, buf_sprintf("cannot assign to constant"));
+// return g->builtin_types.entry_invalid;
+// }
+// return_type = pointer_type->data.pointer.child_type;
+// } else {
+// add_node_error(g, node,
+// buf_sprintf("array access of non-array type '%s'", buf_ptr(&array_type->name)));
+// return_type = g->builtin_types.entry_invalid;
+// }
+//
+// analyze_expression(g, import, context, g->builtin_types.entry_usize, node->data.array_access_expr.subscript);
+//
+// return return_type;
+//}
+//
+//static TypeTableEntry *analyze_logic_bin_op_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
+// AstNode *node)
+//{
+// assert(node->type == NodeTypeBinOpExpr);
+// BinOpType bin_op_type = node->data.bin_op_expr.bin_op;
+//
+// AstNode *op1 = node->data.bin_op_expr.op1;
+// AstNode *op2 = node->data.bin_op_expr.op2;
+// TypeTableEntry *op1_type = analyze_expression(g, import, context, g->builtin_types.entry_bool, op1);
+// TypeTableEntry *op2_type = analyze_expression(g, import, context, g->builtin_types.entry_bool, op2);
+//
+// if (op1_type->id == TypeTableEntryIdInvalid ||
+// op2_type->id == TypeTableEntryIdInvalid)
+// {
+// return g->builtin_types.entry_invalid;
+// }
+//
+// ConstExprValue *op1_val = &get_resolved_expr(op1)->const_val;
+// ConstExprValue *op2_val = &get_resolved_expr(op2)->const_val;
+// if (!op1_val->ok || !op2_val->ok) {
+// return g->builtin_types.entry_bool;
+// }
+//
+// ConstExprValue *out_val = &get_resolved_expr(node)->const_val;
+// eval_const_expr_bin_op(op1_val, op1_type, bin_op_type, op2_val, op2_type, out_val);
+// return g->builtin_types.entry_bool;
+//}
+//
+//static TypeTableEntry *analyze_array_mult(CodeGen *g, ImportTableEntry *import, BlockContext *context,
+// TypeTableEntry *expected_type, AstNode *node)
+//{
+// assert(node->type == NodeTypeBinOpExpr);
+// assert(node->data.bin_op_expr.bin_op == BinOpTypeArrayMult);
+//
+// AstNode **op1 = node->data.bin_op_expr.op1->parent_field;
+// AstNode **op2 = node->data.bin_op_expr.op2->parent_field;
+//
+// TypeTableEntry *op1_type = analyze_expression(g, import, context, nullptr, *op1);
+// TypeTableEntry *op2_type = analyze_expression(g, import, context, nullptr, *op2);
+//
+// if (op1_type->id == TypeTableEntryIdInvalid ||
+// op2_type->id == TypeTableEntryIdInvalid)
+// {
+// return g->builtin_types.entry_invalid;
+// }
+//
+// ConstExprValue *op1_val = &get_resolved_expr(*op1)->const_val;
+// ConstExprValue *op2_val = &get_resolved_expr(*op2)->const_val;
+//
+// AstNode *bad_node;
+// if (!op1_val->ok) {
+// bad_node = *op1;
+// } else if (!op2_val->ok) {
+// bad_node = *op2;
+// } else {
+// bad_node = nullptr;
+// }
+// if (bad_node) {
+// add_node_error(g, bad_node, buf_sprintf("array multiplication requires constant expression"));
+// return g->builtin_types.entry_invalid;
+// }
+//
+// if (op1_type->id != TypeTableEntryIdArray) {
+// add_node_error(g, *op1,
+// buf_sprintf("expected array type, got '%s'", buf_ptr(&op1_type->name)));
+// return g->builtin_types.entry_invalid;
+// }
+//
+// if (op2_type->id != TypeTableEntryIdNumLitInt &&
+// op2_type->id != TypeTableEntryIdInt)
+// {
+// add_node_error(g, *op2, buf_sprintf("expected integer type, got '%s'", buf_ptr(&op2_type->name)));
+// return g->builtin_types.entry_invalid;
+// }
+//
+// if (op2_val->data.x_bignum.is_negative) {
+// add_node_error(g, *op2, buf_sprintf("expected positive number"));
+// return g->builtin_types.entry_invalid;
+// }
+//
+// ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
+// const_val->ok = true;
+// const_val->depends_on_compile_var = op1_val->depends_on_compile_var || op2_val->depends_on_compile_var;
+//
+// TypeTableEntry *child_type = op1_type->data.array.child_type;
+// BigNum old_array_len;
+// bignum_init_unsigned(&old_array_len, op1_type->data.array.len);
+//
+// BigNum new_array_len;
+// if (bignum_mul(&new_array_len, &old_array_len, &op2_val->data.x_bignum)) {
+// add_node_error(g, node, buf_sprintf("operation results in overflow"));
+// return g->builtin_types.entry_invalid;
+// }
+//
+// uint64_t old_array_len_bare = op1_type->data.array.len;
+// uint64_t operand_amt = op2_val->data.x_bignum.data.x_uint;
+//
+// uint64_t new_array_len_bare = new_array_len.data.x_uint;
+// const_val->data.x_array.fields = allocate<ConstExprValue*>(new_array_len_bare);
+//
+// uint64_t i = 0;
+// for (uint64_t x = 0; x < operand_amt; x += 1) {
+// for (uint64_t y = 0; y < old_array_len_bare; y += 1) {
+// const_val->data.x_array.fields[i] = op1_val->data.x_array.fields[y];
+// i += 1;
+// }
+// }
+//
+// return get_array_type(g, child_type, new_array_len_bare);
+//}
+//
+//static TypeTableEntry *analyze_unwrap_error_expr(CodeGen *g, ImportTableEntry *import,
+// BlockContext *parent_context, TypeTableEntry *expected_type, AstNode *node)
+//{
+// AstNode *op1 = node->data.unwrap_err_expr.op1;
+// AstNode *op2 = node->data.unwrap_err_expr.op2;
+// AstNode *var_node = node->data.unwrap_err_expr.symbol;
+//
+// TypeTableEntry *lhs_type = analyze_expression(g, import, parent_context, nullptr, op1);
+// if (lhs_type->id == TypeTableEntryIdInvalid) {
+// return lhs_type;
+// } else if (lhs_type->id == TypeTableEntryIdErrorUnion) {
+// TypeTableEntry *child_type = lhs_type->data.error.child_type;
+// BlockContext *child_context;
+// if (var_node) {
+// child_context = new_block_context(node, parent_context);
+// var_node->block_context = child_context;
+// Buf *var_name = var_node->data.symbol_expr.symbol;
+// node->data.unwrap_err_expr.var = add_local_var(g, var_node, import, child_context, var_name,
+// g->builtin_types.entry_pure_error, true, nullptr);
+// } else {
+// child_context = parent_context;
+// }
+//
+// analyze_expression(g, import, child_context, child_type, op2);
+// return child_type;
+// } else {
+// add_node_error(g, op1,
+// buf_sprintf("expected error type, got '%s'", buf_ptr(&lhs_type->name)));
+// return g->builtin_types.entry_invalid;
+// }
+//}
+//
+//
+//static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTableEntry *import,
+// BlockContext *context, AstNode *source_node,
+// AstNodeVariableDeclaration *variable_declaration,
+// bool expr_is_maybe, AstNode *decl_node, bool var_is_ptr)
+//{
+// bool is_const = variable_declaration->is_const;
+// bool is_export = (variable_declaration->top_level_decl.visib_mod == VisibModExport);
+// bool is_extern = variable_declaration->is_extern;
+//
+// TypeTableEntry *explicit_type = nullptr;
+// if (variable_declaration->type != nullptr) {
+// explicit_type = analyze_type_expr(g, import, context, variable_declaration->type);
+// if (explicit_type->id == TypeTableEntryIdUnreachable) {
+// add_node_error(g, variable_declaration->type,
+// buf_sprintf("variable of type 'unreachable' not allowed"));
+// explicit_type = g->builtin_types.entry_invalid;
+// }
+// }
+//
+// TypeTableEntry *implicit_type = nullptr;
+// if (explicit_type && explicit_type->id == TypeTableEntryIdInvalid) {
+// implicit_type = explicit_type;
+// } else if (variable_declaration->expr) {
+// implicit_type = analyze_expression(g, import, context, explicit_type, variable_declaration->expr);
+// if (implicit_type->id == TypeTableEntryIdInvalid) {
+// // ignore the poison value
+// } else if (expr_is_maybe) {
+// if (implicit_type->id == TypeTableEntryIdMaybe) {
+// if (var_is_ptr) {
+// // TODO if the expression is constant, can't get pointer to it
+// implicit_type = get_pointer_to_type(g, implicit_type->data.maybe.child_type, false);
+// } else {
+// implicit_type = implicit_type->data.maybe.child_type;
+// }
+// } else {
+// add_node_error(g, variable_declaration->expr, buf_sprintf("expected maybe type"));
+// implicit_type = g->builtin_types.entry_invalid;
+// }
+// } else if (implicit_type->id == TypeTableEntryIdUnreachable) {
+// add_node_error(g, source_node,
+// buf_sprintf("variable initialization is unreachable"));
+// implicit_type = g->builtin_types.entry_invalid;
+// } else if ((!is_const || is_export) &&
+// (implicit_type->id == TypeTableEntryIdNumLitFloat ||
+// implicit_type->id == TypeTableEntryIdNumLitInt))
+// {
+// add_node_error(g, source_node, buf_sprintf("unable to infer variable type"));
+// implicit_type = g->builtin_types.entry_invalid;
+// } else if (implicit_type->id == TypeTableEntryIdMetaType && !is_const) {
+// add_node_error(g, source_node, buf_sprintf("variable of type 'type' must be constant"));
+// implicit_type = g->builtin_types.entry_invalid;
+// }
+// if (implicit_type->id != TypeTableEntryIdInvalid && !context->fn_entry) {
+// ConstExprValue *const_val = &get_resolved_expr(variable_declaration->expr)->const_val;
+// if (!const_val->ok) {
+// add_node_error(g, first_executing_node(variable_declaration->expr),
+// buf_sprintf("global variable initializer requires constant expression"));
+// }
+// }
+// } else if (!is_extern) {
+// add_node_error(g, source_node, buf_sprintf("variables must be initialized"));
+// implicit_type = g->builtin_types.entry_invalid;
+// }
+//
+// TypeTableEntry *type = explicit_type != nullptr ? explicit_type : implicit_type;
+// assert(type != nullptr); // should have been caught by the parser
+//
+// VariableTableEntry *var = add_local_var(g, source_node, import, context,
+// variable_declaration->symbol, type, is_const,
+// expr_is_maybe ? nullptr : variable_declaration->expr);
+//
+// variable_declaration->variable = var;
+//
+// return var;
+//}
+//
+//static VariableTableEntry *analyze_variable_declaration(CodeGen *g, ImportTableEntry *import,
+// BlockContext *context, TypeTableEntry *expected_type, AstNode *node)
+//{
+// AstNodeVariableDeclaration *variable_declaration = &node->data.variable_declaration;
+// return analyze_variable_declaration_raw(g, import, context, node, variable_declaration,
+// false, nullptr, false);
+//}
+//
+//static TypeTableEntry *analyze_array_type(CodeGen *g, ImportTableEntry *import, BlockContext *context,
+// TypeTableEntry *expected_type, AstNode *node)
+//{
+// AstNode *size_node = node->data.array_type.size;
+//
+// TypeTableEntry *child_type = analyze_type_expr_pointer_only(g, import, context,
+// node->data.array_type.child_type, true);
+//
+// if (child_type->id == TypeTableEntryIdUnreachable) {
+// add_node_error(g, node, buf_create_from_str("array of unreachable not allowed"));
+// return g->builtin_types.entry_invalid;
+// } else if (child_type->id == TypeTableEntryIdInvalid) {
+// return g->builtin_types.entry_invalid;
+// }
+//
+// if (size_node) {
+// child_type = analyze_type_expr(g, import, context, node->data.array_type.child_type);
+// TypeTableEntry *size_type = analyze_expression(g, import, context,
+// g->builtin_types.entry_usize, size_node);
+// if (size_type->id == TypeTableEntryIdInvalid) {
+// return g->builtin_types.entry_invalid;
+// }
+//
+// ConstExprValue *const_val = &get_resolved_expr(size_node)->const_val;
+// if (const_val->ok) {
+// if (const_val->data.x_bignum.is_negative) {
+// add_node_error(g, size_node,
+// buf_sprintf("array size %s is negative",
+// buf_ptr(bignum_to_buf(&const_val->data.x_bignum))));
+// return g->builtin_types.entry_invalid;
+// } else {
+// return resolve_expr_const_val_as_type(g, node,
+// get_array_type(g, child_type, const_val->data.x_bignum.data.x_uint), false);
+// }
+// } else if (context->fn_entry) {
+// return resolve_expr_const_val_as_type(g, node,
+// get_slice_type(g, child_type, node->data.array_type.is_const), false);
+// } else {
+// add_node_error(g, first_executing_node(size_node),
+// buf_sprintf("unable to evaluate constant expression"));
+// return g->builtin_types.entry_invalid;
+// }
+// } else {
+// TypeTableEntry *slice_type = get_slice_type(g, child_type, node->data.array_type.is_const);
+// return resolve_expr_const_val_as_type(g, node, slice_type, false);
+// }
+//}
+//
+//static TypeTableEntry *analyze_while_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
+// TypeTableEntry *expected_type, AstNode *node)
+//{
+// assert(node->type == NodeTypeWhileExpr);
+//
+// AstNode **condition_node = &node->data.while_expr.condition;
+// AstNode *while_body_node = node->data.while_expr.body;
+// AstNode **continue_expr_node = &node->data.while_expr.continue_expr;
+//
+// TypeTableEntry *condition_type = analyze_expression(g, import, context,
+// g->builtin_types.entry_bool, *condition_node);
+//
+// if (*continue_expr_node) {
+// analyze_expression(g, import, context, g->builtin_types.entry_void, *continue_expr_node);
+// }
+//
+// BlockContext *child_context = new_block_context(node, context);
+// child_context->parent_loop_node = node;
+//
+// analyze_expression(g, import, child_context, g->builtin_types.entry_void, while_body_node);
+//
+//
+// TypeTableEntry *expr_return_type = g->builtin_types.entry_void;
+//
+// if (condition_type->id == TypeTableEntryIdInvalid) {
+// expr_return_type = g->builtin_types.entry_invalid;
+// } else {
+// // if the condition is a simple constant expression and there are no break statements
+// // then the return type is unreachable
+// ConstExprValue *const_val = &get_resolved_expr(*condition_node)->const_val;
+// if (const_val->ok) {
+// if (const_val->data.x_bool) {
+// node->data.while_expr.condition_always_true = true;
+// if (!node->data.while_expr.contains_break) {
+// expr_return_type = g->builtin_types.entry_unreachable;
+// }
+// }
+// }
+// }
+//
+// return expr_return_type;
+//}
+//
+//static TypeTableEntry *analyze_break_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
+// TypeTableEntry *expected_type, AstNode *node)
+//{
+// assert(node->type == NodeTypeBreak);
+//
+// AstNode *loop_node = context->parent_loop_node;
+// if (loop_node) {
+// if (loop_node->type == NodeTypeWhileExpr) {
+// loop_node->data.while_expr.contains_break = true;
+// } else if (loop_node->type == NodeTypeForExpr) {
+// loop_node->data.for_expr.contains_break = true;
+// } else {
+// zig_unreachable();
+// }
+// } else {
+// add_node_error(g, node, buf_sprintf("'break' expression outside loop"));
+// }
+// return g->builtin_types.entry_unreachable;
+//}
+//
+//static TypeTableEntry *analyze_continue_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
+// TypeTableEntry *expected_type, AstNode *node)
+//{
+// AstNode *loop_node = context->parent_loop_node;
+// if (loop_node) {
+// if (loop_node->type == NodeTypeWhileExpr) {
+// loop_node->data.while_expr.contains_continue = true;
+// } else if (loop_node->type == NodeTypeForExpr) {
+// loop_node->data.for_expr.contains_continue = true;
+// } else {
+// zig_unreachable();
+// }
+// } else {
+// add_node_error(g, node, buf_sprintf("'continue' expression outside loop"));
+// }
+// return g->builtin_types.entry_unreachable;
+//}
+//
+//static TypeTableEntry *analyze_defer(CodeGen *g, ImportTableEntry *import, BlockContext *parent_context,
+// TypeTableEntry *expected_type, AstNode *node)
+//{
+// if (!parent_context->fn_entry) {
+// add_node_error(g, node, buf_sprintf("defer expression outside function definition"));
+// return g->builtin_types.entry_invalid;
+// }
+//
+// if (!node->data.defer.expr) {
+// add_node_error(g, node, buf_sprintf("defer expects an expression"));
+// return g->builtin_types.entry_void;
+// }
+//
+// node->data.defer.child_block = new_block_context(node, parent_context);
+//
+// TypeTableEntry *resolved_type = analyze_expression(g, import, parent_context, nullptr,
+// node->data.defer.expr);
+// validate_voided_expr(g, node->data.defer.expr, resolved_type);
+//
+// return g->builtin_types.entry_void;
+//}
+//
+//static TypeTableEntry *analyze_string_literal_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
+// TypeTableEntry *expected_type, AstNode *node)
+//{
+// if (node->data.string_literal.c) {
+// return resolve_expr_const_val_as_c_string_lit(g, node, node->data.string_literal.buf);
+// } else {
+// return resolve_expr_const_val_as_string_lit(g, node, node->data.string_literal.buf);
+// }
+//}
+//
+//static TypeTableEntry *analyze_block_expr(CodeGen *g, ImportTableEntry *import, BlockContext *parent_context,
+// TypeTableEntry *expected_type, AstNode *node)
+//{
+// BlockContext *child_context = new_block_context(node, parent_context);
+// node->data.block.child_block = child_context;
+// TypeTableEntry *return_type = g->builtin_types.entry_void;
+//
+// for (size_t i = 0; i < node->data.block.statements.length; i += 1) {
+// AstNode *child = node->data.block.statements.at(i);
+// if (child->type == NodeTypeLabel) {
+// FnTableEntry *fn_table_entry = child_context->fn_entry;
+// assert(fn_table_entry);
+//
+// LabelTableEntry *label = allocate<LabelTableEntry>(1);
+// label->decl_node = child;
+// label->entered_from_fallthrough = (return_type->id != TypeTableEntryIdUnreachable);
+//
+// child->block_context = child_context;
+// child->data.label.label_entry = label;
+// fn_table_entry->all_labels.append(label);
+//
+// child_context->label_table.put(child->data.label.name, label);
+//
+// return_type = g->builtin_types.entry_void;
+// continue;
+// }
+// if (return_type->id == TypeTableEntryIdUnreachable) {
+// if (is_node_void_expr(child)) {
+// // {unreachable;void;void} is allowed.
+// // ignore void statements once we enter unreachable land.
+// analyze_expression(g, import, child_context, g->builtin_types.entry_void, child);
+// continue;
+// }
+// add_node_error(g, first_executing_node(child), buf_sprintf("unreachable code"));
+// break;
+// }
+// bool is_last = (i == node->data.block.statements.length - 1);
+// TypeTableEntry *passed_expected_type = is_last ? expected_type : nullptr;
+// return_type = analyze_expression(g, import, child_context, passed_expected_type, child);
+// if (child->type == NodeTypeDefer && return_type->id != TypeTableEntryIdInvalid) {
+// // defer starts a new block context
+// child_context = child->data.defer.child_block;
+// assert(child_context);
+// }
+// if (!is_last) {
+// validate_voided_expr(g, child, return_type);
+// }
+// }
+// node->data.block.nested_block = child_context;
+//
+// ConstExprValue *const_val = &node->data.block.resolved_expr.const_val;
+// if (node->data.block.statements.length == 0) {
+// const_val->ok = true;
+// } else if (node->data.block.statements.length == 1) {
+// AstNode *only_node = node->data.block.statements.at(0);
+// ConstExprValue *other_const_val = &get_resolved_expr(only_node)->const_val;
+// if (other_const_val->ok) {
+// *const_val = *other_const_val;
+// }
+// }
+//
+// return return_type;
+//}
+//
+//static TypeTableEntry *analyze_asm_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
+// TypeTableEntry *expected_type, AstNode *node)
+//{
+// mark_impure_fn(g, context, node);
+//
+// node->data.asm_expr.return_count = 0;
+// TypeTableEntry *return_type = g->builtin_types.entry_void;
+// for (size_t i = 0; i < node->data.asm_expr.output_list.length; i += 1) {
+// AsmOutput *asm_output = node->data.asm_expr.output_list.at(i);
+// if (asm_output->return_type) {
+// node->data.asm_expr.return_count += 1;
+// return_type = analyze_type_expr(g, import, context, asm_output->return_type);
+// if (node->data.asm_expr.return_count > 1) {
+// add_node_error(g, node,
+// buf_sprintf("inline assembly allows up to one output value"));
+// break;
+// }
+// } else {
+// Buf *variable_name = asm_output->variable_name;
+// VariableTableEntry *var = find_variable(g, context, variable_name);
+// if (var) {
+// asm_output->variable = var;
+// return var->type;
+// } else {
+// add_node_error(g, node,
+// buf_sprintf("use of undeclared identifier '%s'", buf_ptr(variable_name)));
+// return g->builtin_types.entry_invalid;
+// }
+// }
+// }
+// for (size_t i = 0; i < node->data.asm_expr.input_list.length; i += 1) {
+// AsmInput *asm_input = node->data.asm_expr.input_list.at(i);
+// analyze_expression(g, import, context, nullptr, asm_input->expr);
+// }
+//
+// return return_type;
+//}
+//
+//static TypeTableEntry *analyze_error_literal_expr(CodeGen *g, ImportTableEntry *import,
+// BlockContext *context, AstNode *node, Buf *err_name)
+//{
+// auto err_table_entry = g->error_table.maybe_get(err_name);
+//
+// if (err_table_entry) {
+// return resolve_expr_const_val_as_err(g, node, err_table_entry->value);
+// }
+//
+// add_node_error(g, node,
+// buf_sprintf("use of undeclared error value '%s'", buf_ptr(err_name)));
+//
+// return g->builtin_types.entry_invalid;
+//}
+//
+//static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
+// TypeTableEntry *expected_type, AstNode *node, bool pointer_only)
+//{
+// Buf *variable_name = node->data.symbol_expr.symbol;
+//
+// auto primitive_table_entry = g->primitive_type_table.maybe_get(variable_name);
+// if (primitive_table_entry) {
+// return resolve_expr_const_val_as_type(g, node, primitive_table_entry->value, false);
+// }
+//
+// VariableTableEntry *var = find_variable(g, context, variable_name);
+// if (var) {
+// TypeTableEntry *var_type = analyze_var_ref(g, node, var, context, false);
+// return var_type;
+// }
+//
+// AstNode *decl_node = find_decl(context, variable_name);
+// if (decl_node) {
+// return analyze_decl_ref(g, node, decl_node, pointer_only, context, false);
+// }
+//
+// if (import->any_imports_failed) {
+// // skip the error message since we had a failing import in this file
+// // if an import breaks we don't need 9999 undeclared identifier errors
+// return g->builtin_types.entry_invalid;
+// }
+//
+// mark_impure_fn(g, context, node);
+// add_node_error(g, node, buf_sprintf("use of undeclared identifier '%s'", buf_ptr(variable_name)));
+// return g->builtin_types.entry_invalid;
+//}
+//
+//static TypeTableEntry *analyze_decl_ref(CodeGen *g, AstNode *source_node, AstNode *decl_node,
+// bool pointer_only, BlockContext *block_context, bool depends_on_compile_var)
+//{
+// resolve_top_level_decl(g, decl_node, pointer_only);
+// TopLevelDecl *tld = get_as_top_level_decl(decl_node);
+// if (tld->resolution == TldResolutionInvalid) {
+// return g->builtin_types.entry_invalid;
+// }
+//
+// if (decl_node->type == NodeTypeVariableDeclaration) {
+// 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) {
+// 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 {
+// return resolve_expr_const_val_as_fn(g, source_node, fn_entry, depends_on_compile_var);
+// }
+// } else if (decl_node->type == NodeTypeContainerDecl) {
+// if (decl_node->data.struct_decl.generic_params.length > 0) {
+// TypeTableEntry *type_entry = decl_node->data.struct_decl.generic_fn_type;
+// assert(type_entry);
+// return resolve_expr_const_val_as_generic_fn(g, source_node, type_entry, depends_on_compile_var);
+// } else {
+// return resolve_expr_const_val_as_type(g, source_node, decl_node->data.struct_decl.type_entry,
+// depends_on_compile_var);
+// }
+// } else if (decl_node->type == NodeTypeTypeDecl) {
+// return resolve_expr_const_val_as_type(g, source_node, decl_node->data.type_decl.child_type_entry,
+// depends_on_compile_var);
+// } else {
+// zig_unreachable();
+// }
+//}
+//
+//static TypeTableEntry *analyze_var_ref(CodeGen *g, AstNode *source_node, VariableTableEntry *var,
+// BlockContext *context, bool depends_on_compile_var)
+//{
+// get_resolved_expr(source_node)->variable = var;
+// if (!var_is_pure(var, context)) {
+// mark_impure_fn(g, context, source_node);
+// }
+// if (var->src_is_const && var->val_node) {
+// ConstExprValue *other_const_val = &get_resolved_expr(var->val_node)->const_val;
+// if (other_const_val->ok) {
+// return resolve_expr_const_val_as_other_expr(g, source_node, var->val_node,
+// depends_on_compile_var || var->force_depends_on_compile_var);
+// }
+// }
+// return var->type;
+//}
+//
+//static TypeTableEntry *analyze_null_literal_expr(CodeGen *g, ImportTableEntry *import,
+// BlockContext *block_context, TypeTableEntry *expected_type, AstNode *node)
+//{
+// assert(node->type == NodeTypeNullLiteral);
+//
+// ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
+// const_val->ok = true;
+//
+// return g->builtin_types.entry_null;
+//}
+//
+//static TypeTableEntry *analyze_undefined_literal_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
+// TypeTableEntry *expected_type, AstNode *node)
+//{
+// assert(node->type == NodeTypeUndefinedLiteral);
+//
+// Expr *expr = get_resolved_expr(node);
+// ConstExprValue *const_val = &expr->const_val;
+//
+// const_val->ok = true;
+// const_val->special = ConstValSpecialUndef;
+//
+// return expected_type ? expected_type : g->builtin_types.entry_undef;
+//}
+//
+//static TypeTableEntry *analyze_zeroes_literal_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
+// TypeTableEntry *expected_type, AstNode *node)
+//{
+// Expr *expr = get_resolved_expr(node);
+// ConstExprValue *const_val = &expr->const_val;
+//
+// const_val->ok = true;
+// const_val->special = ConstValSpecialZeroes;
+//
+// return expected_type ? expected_type : g->builtin_types.entry_undef;
+//}
+//
+//static TypeTableEntry *analyze_number_literal_expr(CodeGen *g, ImportTableEntry *import,
+// BlockContext *block_context, TypeTableEntry *expected_type, AstNode *node)
+//{
+// return resolve_expr_const_val_as_bignum(g, node, expected_type, node->data.number_literal.bignum, false);
+//}
+//
+//static TypeTableEntry *analyze_fn_proto_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
+// TypeTableEntry *expected_type, AstNode *node)
+//{
+// TypeTableEntry *type_entry = analyze_fn_proto_type(g, import, context, expected_type, node,
+// false, false, nullptr);
+//
+// if (type_entry->id == TypeTableEntryIdInvalid) {
+// return type_entry;
+// }
+//
+// return resolve_expr_const_val_as_type(g, node, type_entry, false);
+//}
+//
+//static bool var_is_pure(VariableTableEntry *var, BlockContext *context) {
+// if (var->block_context->fn_entry == context->fn_entry) {
+// // variable was declared in the current function, so it's OK.
+// return true;
+// }
+// return var->src_is_const && var->type->deep_const;
+//}
+//
+//static void validate_voided_expr(CodeGen *g, AstNode *source_node, TypeTableEntry *type_entry) {
+// if (type_entry->id == TypeTableEntryIdMetaType) {
+// add_node_error(g, first_executing_node(source_node), buf_sprintf("expected expression, found type"));
+// } else if (type_entry->id == TypeTableEntryIdErrorUnion) {
+// add_node_error(g, first_executing_node(source_node), buf_sprintf("statement ignores error value"));
+// }
+//}
+//
src/ir_print.cpp
@@ -78,6 +78,12 @@ static void ir_print_const_value(IrPrint *irp, TypeTableEntry *type_entry, Const
fprintf(irp->f, "%s", buf_ptr(&fn_entry->symbol_name));
break;
}
+ case TypeTableEntryIdBlock:
+ {
+ AstNode *node = const_val->data.x_block->node;
+ fprintf(irp->f, "(scope:%zu:%zu)", node->line + 1, node->column + 1);
+ break;
+ }
case TypeTableEntryIdVar:
case TypeTableEntryIdFloat:
case TypeTableEntryIdArray:
@@ -91,7 +97,6 @@ static void ir_print_const_value(IrPrint *irp, TypeTableEntry *type_entry, Const
case TypeTableEntryIdUnion:
case TypeTableEntryIdTypeDecl:
case TypeTableEntryIdNamespace:
- case TypeTableEntryIdBlock:
case TypeTableEntryIdGenericFn:
zig_panic("TODO render more constant types in IR printer");
}
@@ -263,18 +268,6 @@ static void ir_print_call(IrPrint *irp, IrInstructionCall *call_instruction) {
fprintf(irp->f, ")");
}
-static void ir_print_builtin_call(IrPrint *irp, IrInstructionBuiltinCall *call_instruction) {
- fprintf(irp->f, "@%s(", buf_ptr(&call_instruction->fn->name));
- for (size_t i = 0; i < call_instruction->fn->param_count; i += 1) {
- IrInstruction *arg = call_instruction->args[i];
- if (i != 0)
- fprintf(irp->f, ", ");
- ir_print_other_instruction(irp, arg);
- }
- fprintf(irp->f, ")");
-}
-
-
static void ir_print_cond_br(IrPrint *irp, IrInstructionCondBr *cond_br_instruction) {
const char *inline_kw = cond_br_instruction->is_inline ? "inline " : "";
fprintf(irp->f, "%sif (", inline_kw);
@@ -393,6 +386,14 @@ static void ir_print_struct_field_ptr(IrPrint *irp, IrInstructionStructFieldPtr
fprintf(irp->f, ")");
}
+static void ir_print_set_fn_test(IrPrint *irp, IrInstructionSetFnTest *instruction) {
+ fprintf(irp->f, "@setFnTest(");
+ ir_print_other_instruction(irp, instruction->fn_value);
+ fprintf(irp->f, ", ");
+ ir_print_other_instruction(irp, instruction->is_test);
+ fprintf(irp->f, ")");
+}
+
static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
ir_print_prefix(irp, instruction);
switch (instruction->id) {
@@ -425,9 +426,6 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdBr:
ir_print_br(irp, (IrInstructionBr *)instruction);
break;
- case IrInstructionIdBuiltinCall:
- ir_print_builtin_call(irp, (IrInstructionBuiltinCall *)instruction);
- break;
case IrInstructionIdPhi:
ir_print_phi(irp, (IrInstructionPhi *)instruction);
break;
@@ -470,6 +468,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdStructFieldPtr:
ir_print_struct_field_ptr(irp, (IrInstructionStructFieldPtr *)instruction);
break;
+ case IrInstructionIdSetFnTest:
+ ir_print_set_fn_test(irp, (IrInstructionSetFnTest *)instruction);
+ break;
case IrInstructionIdSwitchBr:
zig_panic("TODO print more IR instructions");
}
src/parseh.cpp
@@ -230,9 +230,7 @@ static AstNode *create_type_decl_node(Context *c, const char *name, AstNode *chi
}
static AstNode *make_type_node(Context *c, TypeTableEntry *type_entry) {
- AstNode *node = create_node(c, NodeTypeSymbol);
- node->data.symbol_expr.override_type_entry = type_entry;
- return node;
+ zig_panic("TODO bypass AST in parseh");
}
static AstNode *create_fn_proto_node(Context *c, Buf *name, TypeTableEntry *fn_type) {