aboutsummaryrefslogtreecommitdiff
path: root/src/analyze.cpp
diff options
context:
space:
mode:
authorAndrew Kelley <superjoe30@gmail.com>2016-04-14 10:40:08 -0700
committerAndrew Kelley <superjoe30@gmail.com>2016-04-14 10:40:08 -0700
commit579856e502eab87ea8a73a76dc63a2108e5a8cc8 (patch)
treefeb34b0985b29f45073ac81e21982a368e0a3542 /src/analyze.cpp
parent5a479720ec5786145dac6c85deae4e322bd5972e (diff)
parentfcedc35551cc6b14756499414e47c33004de3be4 (diff)
downloadzig-579856e502eab87ea8a73a76dc63a2108e5a8cc8.tar.gz
zig-579856e502eab87ea8a73a76dc63a2108e5a8cc8.zip
Merge branch 'eval'
Diffstat (limited to 'src/analyze.cpp')
-rw-r--r--src/analyze.cpp497
1 files changed, 176 insertions, 321 deletions
diff --git a/src/analyze.cpp b/src/analyze.cpp
index 62b560f0c3..244bdc5fc6 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -13,6 +13,7 @@
#include "parseh.hpp"
#include "config.h"
#include "ast_render.hpp"
+#include "eval.hpp"
static TypeTableEntry *analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context,
TypeTableEntry *expected_type, AstNode *node);
@@ -34,7 +35,8 @@ static TypeTableEntry *resolve_expr_const_val_as_type(CodeGen *g, AstNode *node,
static TypeTableEntry *resolve_expr_const_val_as_unsigned_num_lit(CodeGen *g, AstNode *node,
TypeTableEntry *expected_type, uint64_t x);
static AstNode *find_decl(BlockContext *context, Buf *name);
-static TypeTableEntry *analyze_decl_ref(CodeGen *g, AstNode *source_node, AstNode *decl_node, bool pointer_only);
+static TypeTableEntry *analyze_decl_ref(CodeGen *g, AstNode *source_node, AstNode *decl_node,
+ bool pointer_only, BlockContext *block_context);
static TopLevelDecl *get_as_top_level_decl(AstNode *node);
static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTableEntry *import,
BlockContext *context, AstNode *source_node,
@@ -206,6 +208,7 @@ TypeTableEntry *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x) {
static TypeTableEntry *get_generic_fn_type(CodeGen *g, AstNode *decl_node) {
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdGenericFn);
buf_init_from_str(&entry->name, "(generic function)");
+ entry->deep_const = true;
entry->zero_bits = true;
entry->data.generic_fn.decl_node = decl_node;
return entry;
@@ -219,6 +222,8 @@ TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool
} else {
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdPointer);
+ entry->deep_const = is_const && child_type->deep_const;
+
const char *const_str = is_const ? "const " : "";
buf_resize(&entry->name, 0);
buf_appendf(&entry->name, "&%s%s", const_str, buf_ptr(&child_type->name));
@@ -260,6 +265,8 @@ TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) {
assert(child_type->type_ref);
assert(child_type->di_type);
+ entry->deep_const = child_type->deep_const;
+
buf_resize(&entry->name, 0);
buf_appendf(&entry->name, "?%s", buf_ptr(&child_type->name));
@@ -343,6 +350,8 @@ static TypeTableEntry *get_error_type(CodeGen *g, TypeTableEntry *child_type) {
entry->data.error.child_type = child_type;
+ entry->deep_const = child_type->deep_const;
+
if (!type_has_bits(child_type)) {
entry->type_ref = g->err_tag_type->type_ref;
entry->di_type = g->err_tag_type->di_type;
@@ -414,6 +423,7 @@ TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, uint64_t
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdArray);
entry->type_ref = LLVMArrayType(child_type->type_ref, array_size);
entry->zero_bits = (array_size == 0) || child_type->zero_bits;
+ entry->deep_const = child_type->deep_const;
buf_resize(&entry->name, 0);
buf_appendf(&entry->name, "[%" PRIu64 "]%s", array_size, buf_ptr(&child_type->name));
@@ -464,6 +474,8 @@ TypeTableEntry *get_slice_type(CodeGen *g, TypeTableEntry *child_type, bool is_c
TypeTableEntry *var_peer = get_slice_type(g, child_type, false);
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdStruct);
+ entry->deep_const = child_type->deep_const;
+
buf_resize(&entry->name, 0);
buf_appendf(&entry->name, "[]const %s", buf_ptr(&child_type->name));
@@ -549,6 +561,7 @@ TypeTableEntry *get_typedecl_type(CodeGen *g, const char *name, TypeTableEntry *
buf_init_from_str(&entry->name, name);
+ entry->deep_const = child_type->deep_const;
entry->type_ref = child_type->type_ref;
entry->di_type = child_type->di_type;
entry->zero_bits = child_type->zero_bits;
@@ -572,6 +585,7 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
}
TypeTableEntry *fn_type = new_type_table_entry(TypeTableEntryIdFn);
+ fn_type->deep_const = true;
fn_type->data.fn.fn_type_id = *fn_type_id;
if (fn_type_id->param_info == &fn_type_id->prealloc_param_info[0]) {
fn_type->data.fn.fn_type_id.param_info = &fn_type->data.fn.fn_type_id.prealloc_param_info[0];
@@ -944,6 +958,19 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
add_node_error(g, directive_node,
buf_sprintf("#condition valid only on exported symbols"));
}
+ } else if (buf_eql_str(name, "static_eval_enable")) {
+ if (fn_table_entry->is_extern) {
+ add_node_error(g, directive_node,
+ buf_sprintf("#static_val_enable invalid on extern functions"));
+ } else {
+ bool enable;
+ bool ok = resolve_const_expr_bool(g, import, import->block_context,
+ &directive_node->data.directive.expr, &enable);
+ if (!enable || !ok) {
+ fn_table_entry->is_pure = false;
+ }
+ // TODO cause compile error if enable is true and impure fn
+ }
} else {
add_node_error(g, directive_node,
buf_sprintf("invalid directive: '%s'", buf_ptr(name)));
@@ -1037,6 +1064,8 @@ static void resolve_enum_type(CodeGen *g, ImportTableEntry *import, TypeTableEnt
assert(enum_type->di_type);
+ enum_type->deep_const = true;
+
uint32_t field_count = decl_node->data.struct_decl.fields.length;
enum_type->data.enumeration.field_count = field_count;
@@ -1064,6 +1093,10 @@ static void resolve_enum_type(CodeGen *g, ImportTableEntry *import, TypeTableEnt
type_enum_field->type_entry = field_type;
type_enum_field->value = i;
+ if (!field_type->deep_const) {
+ enum_type->deep_const = false;
+ }
+
di_enumerators[i] = LLVMZigCreateDebugEnumerator(g->dbuilder, buf_ptr(type_enum_field->name), i);
@@ -1224,6 +1257,8 @@ static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableE
assert(struct_type->di_type);
+ struct_type->deep_const = true;
+
int field_count = decl_node->data.struct_decl.fields.length;
struct_type->data.structure.src_field_count = field_count;
@@ -1247,6 +1282,10 @@ static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableE
type_struct_field->src_index = i;
type_struct_field->gen_index = -1;
+ if (!field_type->deep_const) {
+ struct_type->deep_const = false;
+ }
+
if (field_type->id == TypeTableEntryIdStruct) {
resolve_struct_type(g, import, field_type);
} else if (field_type->id == TypeTableEntryIdEnum) {
@@ -1374,6 +1413,7 @@ static void preview_fn_proto_instance(CodeGen *g, ImportTableEntry *import, AstN
fn_table_entry->proto_node = proto_node;
fn_table_entry->fn_def_node = fn_def_node;
fn_table_entry->is_extern = is_extern;
+ fn_table_entry->is_pure = !is_extern;
get_fully_qualified_decl_name(&fn_table_entry->symbol_name, proto_node, '_');
@@ -2201,9 +2241,9 @@ static TypeTableEntry *analyze_container_init_expr(CodeGen *g, ImportTableEntry
const_val->ok = false;
}
}
- if (!const_val->ok) {
- context->fn_entry->struct_val_expr_alloca_list.append(codegen);
- }
+ }
+ if (!const_val->ok) {
+ context->fn_entry->struct_val_expr_alloca_list.append(codegen);
}
for (int i = 0; i < actual_field_count; i += 1) {
@@ -2355,7 +2395,7 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i
AstNode *decl_node = entry ? entry->value : nullptr;
if (decl_node) {
bool pointer_only = false;
- return analyze_decl_ref(g, node, decl_node, pointer_only);
+ return analyze_decl_ref(g, node, decl_node, pointer_only, context);
} else {
add_node_error(g, node,
buf_sprintf("container '%s' has no member called '%s'",
@@ -2382,7 +2422,7 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i
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);
+ return analyze_decl_ref(g, node, decl_node, pointer_only, context);
} else {
const char *import_name = namespace_import->path ? buf_ptr(namespace_import->path) : "(C import)";
add_node_error(g, node,
@@ -2443,6 +2483,12 @@ static TypeTableEntry *analyze_slice_expr(CodeGen *g, ImportTableEntry *import,
return return_type;
}
+static void mark_impure_fn(BlockContext *context) {
+ if (context->fn_entry) {
+ context->fn_entry->is_pure = false;
+ }
+}
+
static TypeTableEntry *analyze_array_access_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
AstNode *node)
{
@@ -2607,26 +2653,6 @@ static TypeTableEntry *resolve_expr_const_val_as_float_num_lit(CodeGen *g, AstNo
return g->builtin_types.entry_num_lit_float;
}
-static TypeTableEntry *resolve_expr_const_val_as_bignum_op(CodeGen *g, AstNode *node,
- bool (*bignum_fn)(BigNum *, BigNum *, BigNum *), AstNode *op1, AstNode *op2,
- TypeTableEntry *resolved_type)
-{
- ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
- ConstExprValue *op1_val = &get_resolved_expr(op1)->const_val;
- ConstExprValue *op2_val = &get_resolved_expr(op2)->const_val;
-
- const_val->ok = true;
-
- if (bignum_fn(&const_val->data.x_bignum, &op1_val->data.x_bignum, &op2_val->data.x_bignum)) {
- add_node_error(g, node,
- buf_sprintf("value cannot be represented in any integer type"));
- } else {
- num_lit_fits_in_other_type(g, node, resolved_type);
- }
-
- return resolved_type;
-}
-
static TypeTableEntry *analyze_error_literal_expr(CodeGen *g, ImportTableEntry *import,
BlockContext *context, AstNode *node, Buf *err_name)
{
@@ -2642,8 +2668,21 @@ static TypeTableEntry *analyze_error_literal_expr(CodeGen *g, ImportTableEntry *
return g->builtin_types.entry_invalid;
}
-static TypeTableEntry *analyze_var_ref(CodeGen *g, AstNode *source_node, VariableTableEntry *var) {
+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->is_const && var->type->deep_const;
+}
+
+static TypeTableEntry *analyze_var_ref(CodeGen *g, AstNode *source_node, VariableTableEntry *var,
+ BlockContext *context)
+{
get_resolved_expr(source_node)->variable = var;
+ if (!var_is_pure(var, context)) {
+ mark_impure_fn(context);
+ }
if (var->is_const && var->val_node) {
ConstExprValue *other_const_val = &get_resolved_expr(var->val_node)->const_val;
if (other_const_val->ok) {
@@ -2654,7 +2693,7 @@ static TypeTableEntry *analyze_var_ref(CodeGen *g, AstNode *source_node, Variabl
}
static TypeTableEntry *analyze_decl_ref(CodeGen *g, AstNode *source_node, AstNode *decl_node,
- bool pointer_only)
+ bool pointer_only, BlockContext *block_context)
{
resolve_top_level_decl(g, decl_node, pointer_only);
TopLevelDecl *tld = get_as_top_level_decl(decl_node);
@@ -2664,7 +2703,7 @@ static TypeTableEntry *analyze_decl_ref(CodeGen *g, AstNode *source_node, AstNod
if (decl_node->type == NodeTypeVariableDeclaration) {
VariableTableEntry *var = decl_node->data.variable_declaration.variable;
- return analyze_var_ref(g, source_node, var);
+ return analyze_var_ref(g, source_node, var, block_context);
} else if (decl_node->type == NodeTypeFnProto) {
if (decl_node->data.fn_proto.generic_params.length > 0) {
TypeTableEntry *type_entry = decl_node->data.fn_proto.generic_fn_type;
@@ -2700,12 +2739,13 @@ static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import,
VariableTableEntry *var = find_variable(g, context, variable_name);
if (var) {
- return analyze_var_ref(g, node, var);
+ TypeTableEntry *var_type = analyze_var_ref(g, node, var, context);
+ return var_type;
}
AstNode *decl_node = find_decl(context, variable_name);
if (decl_node) {
- return analyze_decl_ref(g, node, decl_node, pointer_only);
+ return analyze_decl_ref(g, node, decl_node, pointer_only, context);
}
if (import->any_imports_failed) {
@@ -2840,71 +2880,6 @@ static TypeTableEntry *analyze_lvalue(CodeGen *g, ImportTableEntry *import, Bloc
return expected_rhs_type;
}
-static bool eval_bool_bin_op_bool(bool a, BinOpType bin_op, bool b) {
- if (bin_op == BinOpTypeBoolOr) {
- return a || b;
- } else if (bin_op == BinOpTypeBoolAnd) {
- return a && b;
- } else {
- zig_unreachable();
- }
-}
-
-static bool const_values_equal(ConstExprValue *a, ConstExprValue *b, TypeTableEntry *type_entry) {
- switch (type_entry->id) {
- case TypeTableEntryIdEnum:
- {
- ConstEnumValue *enum1 = &a->data.x_enum;
- ConstEnumValue *enum2 = &b->data.x_enum;
- if (enum1->tag == enum2->tag) {
- TypeEnumField *enum_field = &type_entry->data.enumeration.fields[enum1->tag];
- if (type_has_bits(enum_field->type_entry)) {
- zig_panic("TODO const expr analyze enum special value for equality");
- } else {
- return true;
- }
- }
- return false;
- }
- case TypeTableEntryIdMetaType:
- return a->data.x_type == b->data.x_type;
- case TypeTableEntryIdVoid:
- return true;
- case TypeTableEntryIdPureError:
- return a->data.x_err.err == b->data.x_err.err;
- case TypeTableEntryIdFn:
- return a->data.x_fn == b->data.x_fn;
- case TypeTableEntryIdBool:
- return a->data.x_bool == b->data.x_bool;
- case TypeTableEntryIdInt:
- case TypeTableEntryIdFloat:
- case TypeTableEntryIdNumLitFloat:
- case TypeTableEntryIdNumLitInt:
- return bignum_cmp_eq(&a->data.x_bignum, &b->data.x_bignum);
- case TypeTableEntryIdPointer:
- zig_panic("TODO");
- case TypeTableEntryIdArray:
- zig_panic("TODO");
- case TypeTableEntryIdStruct:
- zig_panic("TODO");
- case TypeTableEntryIdUndefLit:
- zig_panic("TODO");
- case TypeTableEntryIdMaybe:
- zig_panic("TODO");
- case TypeTableEntryIdErrorUnion:
- zig_panic("TODO");
- case TypeTableEntryIdTypeDecl:
- zig_panic("TODO");
- case TypeTableEntryIdNamespace:
- zig_panic("TODO");
- case TypeTableEntryIdGenericFn:
- case TypeTableEntryIdInvalid:
- case TypeTableEntryIdUnreachable:
- zig_unreachable();
- }
- zig_unreachable();
-}
-
static TypeTableEntry *analyze_bool_bin_op_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
AstNode *node)
{
@@ -2944,39 +2919,11 @@ static TypeTableEntry *analyze_bool_bin_op_expr(CodeGen *g, ImportTableEntry *im
return g->builtin_types.entry_bool;
}
- bool answer;
- if (type_can_gt_lt_cmp) {
- bool (*bignum_cmp)(BigNum *, BigNum *);
- if (bin_op_type == BinOpTypeCmpEq) {
- bignum_cmp = bignum_cmp_eq;
- } else if (bin_op_type == BinOpTypeCmpNotEq) {
- bignum_cmp = bignum_cmp_neq;
- } else if (bin_op_type == BinOpTypeCmpLessThan) {
- bignum_cmp = bignum_cmp_lt;
- } else if (bin_op_type == BinOpTypeCmpGreaterThan) {
- bignum_cmp = bignum_cmp_gt;
- } else if (bin_op_type == BinOpTypeCmpLessOrEq) {
- bignum_cmp = bignum_cmp_lte;
- } else if (bin_op_type == BinOpTypeCmpGreaterOrEq) {
- bignum_cmp = bignum_cmp_gte;
- } else {
- zig_unreachable();
- }
- answer = bignum_cmp(&op1_val->data.x_bignum, &op2_val->data.x_bignum);
- } else {
- bool are_equal = const_values_equal(op1_val, op2_val, resolved_type);
- if (bin_op_type == BinOpTypeCmpEq) {
- answer = are_equal;
- } else if (bin_op_type == BinOpTypeCmpNotEq) {
- answer = !are_equal;
- } else {
- zig_unreachable();
- }
- }
+ 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;
- bool depends_on_compile_var = op1_val->depends_on_compile_var || op2_val->depends_on_compile_var;
- return resolve_expr_const_val_as_bool(g, node, answer, depends_on_compile_var);
}
static TypeTableEntry *analyze_logic_bin_op_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
@@ -3002,9 +2949,9 @@ static TypeTableEntry *analyze_logic_bin_op_expr(CodeGen *g, ImportTableEntry *i
return g->builtin_types.entry_bool;
}
- bool answer = eval_bool_bin_op_bool(op1_val->data.x_bool, bin_op_type, op2_val->data.x_bool);
- bool depends_on_compile_var = op1_val->depends_on_compile_var || op2_val->depends_on_compile_var;
- return resolve_expr_const_val_as_bool(g, node, answer, depends_on_compile_var);
+ 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_bin_op_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
@@ -3041,6 +2988,7 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import,
}
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:
@@ -3106,37 +3054,23 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import,
return resolved_type;
}
- if (bin_op_type == BinOpTypeAdd) {
- return resolve_expr_const_val_as_bignum_op(g, node, bignum_add, *op1, *op2, resolved_type);
- } else if (bin_op_type == BinOpTypeSub) {
- return resolve_expr_const_val_as_bignum_op(g, node, bignum_sub, *op1, *op2, resolved_type);
- } else if (bin_op_type == BinOpTypeMult) {
- return resolve_expr_const_val_as_bignum_op(g, node, bignum_mul, *op1, *op2, resolved_type);
- } else if (bin_op_type == BinOpTypeDiv) {
- ConstExprValue *op2_val = &get_resolved_expr(*op2)->const_val;
- if ((is_int && op2_val->data.x_bignum.data.x_uint == 0) ||
- (is_float && op2_val->data.x_bignum.data.x_float == 0.0))
- {
+ 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 {
- return resolve_expr_const_val_as_bignum_op(g, node, bignum_div, *op1, *op2, resolved_type);
+ } 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;
}
- } else if (bin_op_type == BinOpTypeMod) {
- return resolve_expr_const_val_as_bignum_op(g, node, bignum_mod, *op1, *op2, resolved_type);
- } else if (bin_op_type == BinOpTypeBinOr) {
- return resolve_expr_const_val_as_bignum_op(g, node, bignum_or, *op1, *op2, resolved_type);
- } else if (bin_op_type == BinOpTypeBinAnd) {
- return resolve_expr_const_val_as_bignum_op(g, node, bignum_and, *op1, *op2, resolved_type);
- } else if (bin_op_type == BinOpTypeBinXor) {
- return resolve_expr_const_val_as_bignum_op(g, node, bignum_xor, *op1, *op2, resolved_type);
- } else if (bin_op_type == BinOpTypeBitShiftLeft) {
- return resolve_expr_const_val_as_bignum_op(g, node, bignum_shl, *op1, *op2, resolved_type);
- } else if (bin_op_type == BinOpTypeBitShiftRight) {
- return resolve_expr_const_val_as_bignum_op(g, node, bignum_shr, *op1, *op2, resolved_type);
- } else {
- zig_unreachable();
+ return g->builtin_types.entry_invalid;
}
+
+ num_lit_fits_in_other_type(g, node, resolved_type);
+ return resolved_type;
}
case BinOpTypeUnwrapMaybe:
{
@@ -3720,6 +3654,10 @@ static TypeTableEntry *analyze_if_bool_expr(CodeGen *g, ImportTableEntry *import
}
ConstExprValue *cond_val = &get_resolved_expr(*cond)->const_val;
+ if (cond_val->undef) {
+ 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),
@@ -3762,17 +3700,6 @@ static TypeTableEntry *analyze_if_var_expr(CodeGen *g, ImportTableEntry *import,
node, then_node, else_node, cond_is_const, cond_bool_val);
}
-static bool int_type_depends_on_compile_var(CodeGen *g, TypeTableEntry *int_type) {
- assert(int_type->id == TypeTableEntryIdInt);
-
- for (int i = 0; i < CIntTypeCount; i += 1) {
- if (int_type == g->builtin_types.entry_c_int[i]) {
- return true;
- }
- }
- return false;
-}
-
static TypeTableEntry *analyze_min_max_value(CodeGen *g, ImportTableEntry *import, BlockContext *context,
AstNode *node, const char *err_format, bool is_max)
{
@@ -3781,67 +3708,15 @@ static TypeTableEntry *analyze_min_max_value(CodeGen *g, ImportTableEntry *impor
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) {
- ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
- const_val->ok = true;
- const_val->depends_on_compile_var = int_type_depends_on_compile_var(g, type_entry);
- if (is_max) {
- if (type_entry->data.integral.is_signed) {
- int64_t val;
- if (type_entry->data.integral.bit_count == 64) {
- val = INT64_MAX;
- } else if (type_entry->data.integral.bit_count == 32) {
- val = INT32_MAX;
- } else if (type_entry->data.integral.bit_count == 16) {
- val = INT16_MAX;
- } else if (type_entry->data.integral.bit_count == 8) {
- val = INT8_MAX;
- } else {
- zig_unreachable();
- }
- bignum_init_signed(&const_val->data.x_bignum, val);
- } else {
- uint64_t val;
- if (type_entry->data.integral.bit_count == 64) {
- val = UINT64_MAX;
- } else if (type_entry->data.integral.bit_count == 32) {
- val = UINT32_MAX;
- } else if (type_entry->data.integral.bit_count == 16) {
- val = UINT16_MAX;
- } else if (type_entry->data.integral.bit_count == 8) {
- val = UINT8_MAX;
- } else {
- zig_unreachable();
- }
- bignum_init_unsigned(&const_val->data.x_bignum, val);
- }
- } else {
- if (type_entry->data.integral.is_signed) {
- int64_t val;
- if (type_entry->data.integral.bit_count == 64) {
- val = INT64_MIN;
- } else if (type_entry->data.integral.bit_count == 32) {
- val = INT32_MIN;
- } else if (type_entry->data.integral.bit_count == 16) {
- val = INT16_MIN;
- } else if (type_entry->data.integral.bit_count == 8) {
- val = INT8_MIN;
- } else {
- zig_unreachable();
- }
- bignum_init_signed(&const_val->data.x_bignum, val);
- } else {
- bignum_init_unsigned(&const_val->data.x_bignum, 0);
- }
- }
- return type_entry;
- } else if (type_entry->id == TypeTableEntryIdFloat) {
- zig_panic("TODO analyze_min_max_value float");
+ } else if (type_entry->id == TypeTableEntryIdInt ||
+ type_entry->id == TypeTableEntryIdFloat ||
+ type_entry->id == TypeTableEntryIdBool)
+ {
+ eval_min_max_value(g, type_entry, &get_resolved_expr(node)->const_val, is_max);
return type_entry;
- } else if (type_entry->id == TypeTableEntryIdBool) {
- return resolve_expr_const_val_as_bool(g, node, is_max, false);
} else {
add_node_error(g, node,
buf_sprintf(err_format, buf_ptr(&type_entry->name)));
@@ -3849,92 +3724,19 @@ static TypeTableEntry *analyze_min_max_value(CodeGen *g, ImportTableEntry *impor
}
}
-static void eval_const_expr_implicit_cast(CodeGen *g, AstNode *node, AstNode *expr_node) {
- assert(node->type == NodeTypeFnCallExpr);
- ConstExprValue *other_val = &get_resolved_expr(expr_node)->const_val;
- ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
- if (!other_val->ok) {
- return;
- }
- const_val->depends_on_compile_var = other_val->depends_on_compile_var;
- const_val->undef = other_val->undef;
-
- assert(other_val != const_val);
- switch (node->data.fn_call_expr.cast_op) {
- case CastOpNoCast:
- zig_unreachable();
- case CastOpNoop:
- case CastOpWidenOrShorten:
- case CastOpPointerReinterpret:
- *const_val = *other_val;
- break;
- case CastOpPtrToInt:
- case CastOpIntToPtr:
- // can't do it
- break;
- case CastOpToUnknownSizeArray:
- {
- TypeTableEntry *other_type = get_resolved_expr(expr_node)->type_entry;
- assert(other_type->id == TypeTableEntryIdArray);
-
- ConstExprValue *all_fields = allocate<ConstExprValue>(2);
- ConstExprValue *ptr_field = &all_fields[0];
- ConstExprValue *len_field = &all_fields[1];
-
- const_val->data.x_struct.fields = allocate<ConstExprValue*>(2);
- const_val->data.x_struct.fields[0] = ptr_field;
- const_val->data.x_struct.fields[1] = len_field;
-
- ptr_field->ok = true;
- ptr_field->data.x_ptr.ptr = other_val->data.x_array.fields;
- ptr_field->data.x_ptr.len = other_type->data.array.len;
-
- len_field->ok = true;
- bignum_init_unsigned(&len_field->data.x_bignum, other_type->data.array.len);
-
- const_val->ok = true;
- break;
- }
- case CastOpMaybeWrap:
- const_val->data.x_maybe = other_val;
- const_val->ok = true;
- break;
- case CastOpErrorWrap:
- const_val->data.x_err.err = nullptr;
- const_val->data.x_err.payload = other_val;
- const_val->ok = true;
- break;
- case CastOpPureErrorWrap:
- const_val->data.x_err.err = other_val->data.x_err.err;
- const_val->ok = true;
- break;
- case CastOpErrToInt:
- {
- uint64_t value = other_val->data.x_err.err ? other_val->data.x_err.err->value : 0;
- bignum_init_unsigned(&const_val->data.x_bignum, value);
- const_val->ok = true;
- break;
- }
- case CastOpIntToFloat:
- bignum_cast_to_float(&const_val->data.x_bignum, &other_val->data.x_bignum);
- const_val->ok = true;
- break;
- case CastOpFloatToInt:
- bignum_cast_to_int(&const_val->data.x_bignum, &other_val->data.x_bignum);
- const_val->ok = true;
- break;
- case CastOpBoolToInt:
- bignum_init_unsigned(&const_val->data.x_bignum, other_val->data.x_bool ? 1 : 0);
- const_val->ok = true;
- break;
- }
-}
-
static TypeTableEntry *resolve_cast(CodeGen *g, BlockContext *context, AstNode *node,
AstNode *expr_node, TypeTableEntry *wanted_type, CastOp op, bool need_alloca)
{
node->data.fn_call_expr.cast_op = op;
- eval_const_expr_implicit_cast(g, node, expr_node);
+
+ ConstExprValue *other_val = &get_resolved_expr(expr_node)->const_val;
+ TypeTableEntry *other_type = get_resolved_expr(expr_node)->type_entry;
+ ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
+ if (other_val->ok) {
+ eval_const_expr_implicit_cast(node->data.fn_call_expr.cast_op, other_val, other_type,
+ const_val, wanted_type);
+ }
+
if (need_alloca) {
if (context->fn_entry) {
context->fn_entry->cast_alloca_list.append(node);
@@ -4630,13 +4432,15 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry
case BuiltinFnIdErrName:
return analyze_err_name(g, import, context, node);
case BuiltinFnIdBreakpoint:
+ mark_impure_fn(context);
return g->builtin_types.entry_void;
}
zig_unreachable();
}
static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
- TypeTableEntry *expected_type, AstNode *node, TypeTableEntry *fn_type, TypeTableEntry *struct_type)
+ TypeTableEntry *expected_type, AstNode *node, TypeTableEntry *fn_type,
+ AstNode *struct_node)
{
assert(node->type == NodeTypeFnCallExpr);
@@ -4648,31 +4452,49 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import,
int src_param_count = fn_type->data.fn.fn_type_id.param_count;
int actual_param_count = node->data.fn_call_expr.params.length;
- if (struct_type) {
+ if (struct_node) {
actual_param_count += 1;
}
+ bool ok_invocation = true;
+
if (fn_type->data.fn.fn_type_id.is_var_args) {
if (actual_param_count < src_param_count) {
+ ok_invocation = false;
add_node_error(g, node,
buf_sprintf("expected at least %d arguments, got %d", src_param_count, actual_param_count));
}
} else if (src_param_count != actual_param_count) {
+ ok_invocation = false;
add_node_error(g, node,
buf_sprintf("expected %d arguments, got %d", src_param_count, actual_param_count));
}
+ bool all_args_const_expr = true;
+
+ if (struct_node) {
+ ConstExprValue *struct_const_val = &get_resolved_expr(struct_node)->const_val;
+ if (!struct_const_val->ok) {
+ all_args_const_expr = false;
+ }
+ }
+
// analyze each parameter. in the case of a method, we already analyzed the
// first parameter in order to figure out which struct we were calling a method on.
for (int i = 0; i < node->data.fn_call_expr.params.length; i += 1) {
- AstNode *child = node->data.fn_call_expr.params.at(i);
+ AstNode **child = &node->data.fn_call_expr.params.at(i);
// determine the expected type for each parameter
TypeTableEntry *expected_param_type = nullptr;
- int fn_proto_i = i + (struct_type ? 1 : 0);
+ int fn_proto_i = i + (struct_node ? 1 : 0);
if (fn_proto_i < src_param_count) {
expected_param_type = fn_type->data.fn.fn_type_id.param_info[fn_proto_i].type;
}
- analyze_expression(g, import, context, expected_param_type, child);
+ analyze_expression(g, import, context, expected_param_type, *child);
+
+ ConstExprValue *const_arg_val = &get_resolved_expr(*child)->const_val;
+ if (!const_arg_val->ok) {
+ all_args_const_expr = false;
+ }
}
TypeTableEntry *return_type = fn_type->data.fn.fn_type_id.return_type;
@@ -4681,6 +4503,27 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import,
return return_type;
}
+ FnTableEntry *fn_table_entry = node->data.fn_call_expr.fn_entry;
+ if (ok_invocation && fn_table_entry && fn_table_entry->is_pure) {
+ if (fn_table_entry->anal_state == FnAnalStateReady) {
+ analyze_fn_body(g, fn_table_entry);
+ }
+ if (all_args_const_expr) {
+ if (fn_table_entry->is_pure && fn_table_entry->anal_state == FnAnalStateComplete) {
+ ConstExprValue *result_val = &get_resolved_expr(node)->const_val;
+ 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) {
+ // calling an impure fn is impure
+ mark_impure_fn(context);
+ }
+
if (handle_is_ptr(return_type)) {
context->fn_entry->cast_alloca_list.append(node);
}
@@ -4689,13 +4532,13 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import,
}
static TypeTableEntry *analyze_fn_call_raw(CodeGen *g, ImportTableEntry *import, BlockContext *context,
- TypeTableEntry *expected_type, AstNode *node, FnTableEntry *fn_table_entry, TypeTableEntry *struct_type)
+ TypeTableEntry *expected_type, AstNode *node, FnTableEntry *fn_table_entry, AstNode *struct_node)
{
assert(node->type == NodeTypeFnCallExpr);
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_type);
+ return analyze_fn_call_ptr(g, import, context, expected_type, node, fn_table_entry->type_entry, struct_node);
}
static TypeTableEntry *analyze_generic_fn_call(CodeGen *g, ImportTableEntry *import, BlockContext *parent_context,
@@ -4721,7 +4564,7 @@ static TypeTableEntry *analyze_generic_fn_call(CodeGen *g, ImportTableEntry *imp
generic_fn_type_id->generic_param_count = actual_param_count;
generic_fn_type_id->generic_params = allocate<GenericParamValue>(actual_param_count);
- BlockContext *child_context = import->block_context;
+ BlockContext *child_context = decl_node->owner->block_context;
for (int i = 0; i < actual_param_count; i += 1) {
AstNode *generic_param_decl_node = decl_node->data.fn_proto.generic_params.at(i);
assert(generic_param_decl_node->type == NodeTypeParamDecl);
@@ -4861,17 +4704,17 @@ static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import
return analyze_cast_expr(g, import, context, node);
}
} else if (invoke_type_entry->id == TypeTableEntryIdFn) {
- TypeTableEntry *bare_struct_type;
+ AstNode *struct_node;
if (fn_ref_expr->type == NodeTypeFieldAccessExpr &&
fn_ref_expr->data.field_access_expr.is_member_fn)
{
- bare_struct_type = fn_ref_expr->data.field_access_expr.bare_struct_type;
+ struct_node = fn_ref_expr->data.field_access_expr.struct_expr;
} else {
- bare_struct_type = nullptr;
+ struct_node = nullptr;
}
return analyze_fn_call_raw(g, import, context, expected_type, node,
- const_val->data.x_fn, bare_struct_type);
+ const_val->data.x_fn, struct_node);
} else if (invoke_type_entry->id == TypeTableEntryIdGenericFn) {
return analyze_generic_fn_call(g, import, context, expected_type, node, const_val->data.x_type);
} else {
@@ -5421,6 +5264,8 @@ static TypeTableEntry *analyze_block_expr(CodeGen *g, ImportTableEntry *import,
static TypeTableEntry *analyze_asm_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
TypeTableEntry *expected_type, AstNode *node)
{
+ mark_impure_fn(context);
+
node->data.asm_expr.return_count = 0;
TypeTableEntry *return_type = g->builtin_types.entry_void;
for (int i = 0; i < node->data.asm_expr.output_list.length; i += 1) {
@@ -5641,8 +5486,10 @@ static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) {
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;
@@ -5676,6 +5523,10 @@ static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) {
param_decl_node->data.param_decl.variable = var;
var->gen_arg_index = fn_type->data.fn.gen_param_info[i].gen_index;
+
+ if (!type->deep_const) {
+ fn_table_entry->is_pure = false;
+ }
}
TypeTableEntry *expected_type = fn_type->data.fn.fn_type_id.return_type;
@@ -5697,6 +5548,8 @@ static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) {
buf_ptr(&label->decl_node->data.label.name)));
}
}
+
+ fn_table_entry->anal_state = FnAnalStateComplete;
}
static void add_top_level_decl(CodeGen *g, ImportTableEntry *import, BlockContext *block_context,
@@ -6005,7 +5858,9 @@ void semantic_analyze(CodeGen *g) {
for (int i = 0; i < g->fn_defs.length; i += 1) {
FnTableEntry *fn_entry = g->fn_defs.at(i);
- analyze_fn_body(g, fn_entry);
+ if (fn_entry->anal_state == FnAnalStateReady) {
+ analyze_fn_body(g, fn_entry);
+ }
}
}