From be4df96e4b80a3307b3661fd5ca3114478499daf Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 12 Apr 2016 13:30:52 -0700 Subject: passing all tests --- test/run_tests.cpp | 124 ++--------------------------------------------------- 1 file changed, 3 insertions(+), 121 deletions(-) (limited to 'test/run_tests.cpp') diff --git a/test/run_tests.cpp b/test/run_tests.cpp index 4143fa000e..f9f5707bca 100644 --- a/test/run_tests.cpp +++ b/test/run_tests.cpp @@ -218,6 +218,7 @@ pub fn bar_function() { )SOURCE"); add_source_file(tc, "other.zig", R"SOURCE( +#static_eval_enable(false) pub fn foo_function() -> bool { // this one conflicts with the one from foo return true; @@ -406,20 +407,6 @@ pub fn main(args: [][]u8) -> %void { } )SOURCE", "loop\nloop\nloop\nloop\n"); - add_simple_case("implicit cast after unreachable", R"SOURCE( -const io = @import("std").io; -pub fn main(args: [][]u8) -> %void { - const x = outer(); - if (x == 1234) { - %%io.stdout.printf("OK\n"); - } -} -fn inner() -> i32 { 1234 } -fn outer() -> isize { - return inner(); -} - )SOURCE", "OK\n"); - add_simple_case("@sizeof() and @typeof()", R"SOURCE( const io = @import("std").io; const x: u16 = 13; @@ -431,23 +418,6 @@ pub fn main(args: [][]u8) -> %void { } )SOURCE", "2\n"); - add_simple_case("member functions", R"SOURCE( -const io = @import("std").io; -struct Rand { - seed: u32, - pub fn get_seed(r: Rand) -> u32 { - r.seed - } -} -pub fn main(args: [][]u8) -> %void { - const r = Rand {.seed = 1234}; - if (r.get_seed() != 1234) { - %%io.stdout.printf("BAD seed\n"); - } - %%io.stdout.printf("OK\n"); -} - )SOURCE", "OK\n"); - add_simple_case("pointer dereferencing", R"SOURCE( const io = @import("std").io; @@ -565,24 +535,6 @@ pub fn main(args: [][]u8) -> %void { "min i64: -9223372036854775808\n"); - add_simple_case("else if expression", R"SOURCE( -const io = @import("std").io; -pub fn main(args: [][]u8) -> %void { - if (f(1) == 1) { - %%io.stdout.printf("OK\n"); - } -} -fn f(c: u8) -> u8 { - if (c == 0) { - 0 - } else if (c == 1) { - 1 - } else { - 2 - } -} - )SOURCE", "OK\n"); - add_simple_case("overflow intrinsics", R"SOURCE( const io = @import("std").io; pub fn main(args: [][]u8) -> %void { @@ -730,29 +682,6 @@ pub fn main(args: [][]u8) -> %void { } )SOURCE", "OK\n"); - add_simple_case("%% binary operator", R"SOURCE( -const io = @import("std").io; -error ItBroke; -fn g(x: bool) -> %isize { - if (x) { - error.ItBroke - } else { - 10 - } -} -pub fn main(args: [][]u8) -> %void { - const a = g(true) %% 3; - const b = g(false) %% 3; - if (a != 3) { - %%io.stdout.printf("BAD\n"); - } - if (b != 10) { - %%io.stdout.printf("BAD\n"); - } - %%io.stdout.printf("OK\n"); -} - )SOURCE", "OK\n"); - add_simple_case("string concatenation", R"SOURCE( const io = @import("std").io; pub fn main(args: [][]u8) -> %void { @@ -808,54 +737,6 @@ pub fn main(args: [][]u8) -> %void { } )SOURCE", "OK\n"); - add_simple_case("unwrap simple value from error", R"SOURCE( -const io = @import("std").io; -fn do() -> %isize { - 13 -} - -pub fn main(args: [][]u8) -> %void { - const i = %%do(); - if (i != 13) { - %%io.stdout.printf("BAD\n"); - } - %%io.stdout.printf("OK\n"); -} - )SOURCE", "OK\n"); - - add_simple_case("store member function in variable", R"SOURCE( -const io = @import("std").io; -struct Foo { - x: i32, - fn member(foo: Foo) -> i32 { foo.x } -} -pub fn main(args: [][]u8) -> %void { - const instance = Foo { .x = 1234, }; - const member_fn = Foo.member; - const result = member_fn(instance); - if (result != 1234) { - %%io.stdout.printf("BAD\n"); - } - %%io.stdout.printf("OK\n"); -} - )SOURCE", "OK\n"); - - add_simple_case("call member function directly", R"SOURCE( -const io = @import("std").io; -struct Foo { - x: i32, - fn member(foo: Foo) -> i32 { foo.x } -} -pub fn main(args: [][]u8) -> %void { - const instance = Foo { .x = 1234, }; - const result = Foo.member(instance); - if (result != 1234) { - %%io.stdout.printf("BAD\n"); - } - %%io.stdout.printf("OK\n"); -} - )SOURCE", "OK\n"); - add_simple_case("call result of if else expression", R"SOURCE( const io = @import("std").io; fn a() -> []u8 { "a\n" } @@ -1496,7 +1377,8 @@ fn a(x: i32) { struct Foo { y: [get()]u8, } -fn get() -> isize { 1 } +var global_var: isize = 1; +fn get() -> isize { global_var } )SOURCE", 1, ".tmp_source.zig:3:9: error: unable to evaluate constant expression"); -- cgit v1.2.3 From 69109bc270c3167a3534dd32fc4f4def855e0be9 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 12 Apr 2016 16:18:41 -0700 Subject: add error for dividing by zero in static function evaluation --- src/analyze.cpp | 60 ++++++++++++------------------------------------------ src/error.cpp | 2 ++ src/error.hpp | 2 ++ src/eval.cpp | 47 +++++++++++++++++++++++++++++++++--------- src/eval.hpp | 2 +- test/run_tests.cpp | 10 +++++++++ 6 files changed, 65 insertions(+), 58 deletions(-) (limited to 'test/run_tests.cpp') diff --git a/src/analyze.cpp b/src/analyze.cpp index f7ef77c195..0cd234e3b8 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -2653,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) { @@ -3074,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: { diff --git a/src/error.cpp b/src/error.cpp index 7690dd0776..caed95f693 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -12,6 +12,8 @@ const char *err_str(int err) { case ErrorFileNotFound: return "file not found"; case ErrorFileSystem: return "file system error"; case ErrorFileTooBig: return "file too big"; + case ErrorDivByZero: return "division by zero"; + case ErrorOverflow: return "overflow"; } return "(invalid error)"; } diff --git a/src/error.hpp b/src/error.hpp index 742f30700e..7fea3ccfbb 100644 --- a/src/error.hpp +++ b/src/error.hpp @@ -19,6 +19,8 @@ enum Error { ErrorFileNotFound, ErrorFileSystem, ErrorFileTooBig, + ErrorDivByZero, + ErrorOverflow }; const char *err_str(int err); diff --git a/src/eval.cpp b/src/eval.cpp index 1e386e0368..3e9d836a3e 100644 --- a/src/eval.cpp +++ b/src/eval.cpp @@ -1,5 +1,6 @@ #include "eval.hpp" #include "analyze.hpp" +#include "error.hpp" static bool eval_fn_args(EvalFnRoot *efr, FnTableEntry *fn, ConstExprValue *args, ConstExprValue *out_val); @@ -96,16 +97,20 @@ static bool eval_bool_bin_op_bool(bool a, BinOpType bin_op, bool b) { } } -static void eval_const_expr_bin_op_bignum(ConstExprValue *op1_val, ConstExprValue *op2_val, +static int eval_const_expr_bin_op_bignum(ConstExprValue *op1_val, ConstExprValue *op2_val, ConstExprValue *out_val, bool (*bignum_fn)(BigNum *, BigNum *, BigNum *)) { bool overflow = bignum_fn(&out_val->data.x_bignum, &op1_val->data.x_bignum, &op2_val->data.x_bignum); - assert(!overflow); + if (overflow) { + return ErrorOverflow; + } + out_val->ok = true; out_val->depends_on_compile_var = op1_val->depends_on_compile_var || op2_val->depends_on_compile_var; + return 0; } -void eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type, +int eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type, BinOpType bin_op, ConstExprValue *op2_val, TypeTableEntry *op2_type, ConstExprValue *out_val) { assert(op1_val->ok); @@ -126,7 +131,7 @@ void eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type, case BinOpTypeAssignBoolAnd: case BinOpTypeAssignBoolOr: out_val->ok = true; - return; + return 0; case BinOpTypeBoolOr: case BinOpTypeBoolAnd: assert(op1_type->id == TypeTableEntryIdBool); @@ -134,7 +139,7 @@ void eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type, out_val->data.x_bool = eval_bool_bin_op_bool(op1_val->data.x_bool, bin_op, op2_val->data.x_bool); out_val->ok = true; out_val->depends_on_compile_var = op1_val->depends_on_compile_var || op2_val->depends_on_compile_var; - return; + return 0; case BinOpTypeCmpEq: case BinOpTypeCmpNotEq: case BinOpTypeCmpLessThan: @@ -181,7 +186,7 @@ void eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type, op1_val->depends_on_compile_var || op2_val->depends_on_compile_var; out_val->data.x_bool = answer; out_val->ok = true; - return; + return 0; } case BinOpTypeAdd: return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_add); @@ -215,7 +220,7 @@ void eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type, if ((is_int && op2_val->data.x_bignum.data.x_uint == 0) || (is_float && op2_val->data.x_bignum.data.x_float == 0.0)) { - zig_panic("TODO handle errors in eval"); + return ErrorDivByZero; } else { return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_div); } @@ -249,7 +254,26 @@ static bool eval_bin_op_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) BinOpType bin_op = node->data.bin_op_expr.bin_op; - eval_const_expr_bin_op(&op1_val, op1_type, bin_op, &op2_val, op2_type, out_val); + int err; + if ((err = eval_const_expr_bin_op(&op1_val, op1_type, bin_op, &op2_val, op2_type, out_val))) { + ef->root->abort = true; + if (err == ErrorDivByZero) { + ErrorMsg *msg = add_node_error(ef->root->codegen, ef->root->fn->fn_def_node, + buf_sprintf("function evaluation caused division by zero")); + add_error_note(ef->root->codegen, msg, ef->root->call_node, buf_sprintf("called from here")); + add_error_note(ef->root->codegen, msg, node, buf_sprintf("division by zero here")); + } else if (err == ErrorOverflow) { + ErrorMsg *msg = add_node_error(ef->root->codegen, ef->root->fn->fn_def_node, + buf_sprintf("function evaluation caused overflow")); + add_error_note(ef->root->codegen, msg, ef->root->call_node, buf_sprintf("called from here")); + add_error_note(ef->root->codegen, msg, node, buf_sprintf("overflow occurred here")); + } else { + zig_unreachable(); + } + return true; + } + + assert(out_val->ok); return false; } @@ -1133,8 +1157,11 @@ bool eval_fn(CodeGen *g, AstNode *node, FnTableEntry *fn, ConstExprValue *out_va return true; } - assert(out_val->ok); + if (efr.abort) { + return true; + } - return efr.abort; + assert(out_val->ok); + return false; } diff --git a/src/eval.hpp b/src/eval.hpp index f8266228fb..e0236b7146 100644 --- a/src/eval.hpp +++ b/src/eval.hpp @@ -14,7 +14,7 @@ bool eval_fn(CodeGen *g, AstNode *node, FnTableEntry *fn, ConstExprValue *out_va AstNode *struct_node); bool const_values_equal(ConstExprValue *a, ConstExprValue *b, TypeTableEntry *type_entry); -void eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type, +int eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type, BinOpType bin_op, ConstExprValue *op2_val, TypeTableEntry *op2_type, ConstExprValue *out_val); void eval_const_expr_implicit_cast(CastOp cast_op, diff --git a/test/run_tests.cpp b/test/run_tests.cpp index f9f5707bca..5b3d68e72b 100644 --- a/test/run_tests.cpp +++ b/test/run_tests.cpp @@ -1481,6 +1481,16 @@ fn foo() { const pointer = &array[0]; } )SOURCE", 1, ".tmp_source.zig:4:27: error: out of bounds array access"); + + add_compile_fail_case("compile time division by zero", R"SOURCE( +const x = foo(0); +fn foo(x: i32) -> i32 { + 1 / x +} + )SOURCE", 3, + ".tmp_source.zig:3:1: error: function evaluation caused division by zero", + ".tmp_source.zig:2:14: note: called from here", + ".tmp_source.zig:4:7: note: division by zero here"); } ////////////////////////////////////////////////////////////////////////////// -- cgit v1.2.3 From 3c27cb25279049cfdcde99d49045f5b8ec8981ba Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 12 Apr 2016 17:33:46 -0700 Subject: more eval tests and fix eval call analyze code --- src/analyze.cpp | 17 ++++++---------- src/eval.cpp | 4 +++- test/run_tests.cpp | 15 ++++++++++++++ test/self_hosted.zig | 56 +++++++++++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 77 insertions(+), 15 deletions(-) (limited to 'test/run_tests.cpp') diff --git a/src/analyze.cpp b/src/analyze.cpp index 0cd234e3b8..f24d538ad8 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -4504,28 +4504,23 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import, } FnTableEntry *fn_table_entry = node->data.fn_call_expr.fn_entry; - if (ok_invocation && fn_table_entry && fn_table_entry->is_pure && all_args_const_expr) { + 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); - } else if (fn_table_entry->anal_state == FnAnalStateProbing) { - mark_impure_fn(context); } - if (fn_table_entry->is_pure) { - if (fn_table_entry->anal_state == FnAnalStateComplete) { + 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; - } else if (fn_table_entry->anal_state == FnAnalStateSkipped) { - return g->builtin_types.entry_invalid; } - } else { - // calling an impure fn is impure - mark_impure_fn(context); } - } else { + } + if (!ok_invocation || !fn_table_entry || !fn_table_entry->is_pure) { + // calling an impure fn is impure mark_impure_fn(context); } diff --git a/src/eval.cpp b/src/eval.cpp index 3e9d836a3e..34656c41e1 100644 --- a/src/eval.cpp +++ b/src/eval.cpp @@ -713,7 +713,9 @@ static bool eval_fn_call_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val } if (!fn_table_entry) { - zig_panic("TODO"); + ConstExprValue fn_val = {0}; + if (eval_expr(ef, fn_ref_expr, &fn_val)) return true; + fn_table_entry = fn_val.data.x_fn; } int param_count = node->data.fn_call_expr.params.length; diff --git a/test/run_tests.cpp b/test/run_tests.cpp index 5b3d68e72b..461ee4172c 100644 --- a/test/run_tests.cpp +++ b/test/run_tests.cpp @@ -1491,6 +1491,21 @@ fn foo(x: i32) -> i32 { ".tmp_source.zig:3:1: error: function evaluation caused division by zero", ".tmp_source.zig:2:14: note: called from here", ".tmp_source.zig:4:7: note: division by zero here"); + + add_compile_fail_case("branch on undefined value", R"SOURCE( +const x = if (undefined) true else false; + )SOURCE", 1, ".tmp_source.zig:2:15: error: branch on undefined value"); + + + add_compile_fail_case("endless loop in function evaluation", R"SOURCE( +const seventh_fib_number = fibbonaci(7); +fn fibbonaci(x: i32) -> i32 { + return fibbonaci(x - 1) + fibbonaci(x - 2); +} + )SOURCE", 3, + ".tmp_source.zig:3:1: error: function evaluation exceeded 1000 branches", + ".tmp_source.zig:2:37: note: called from here", + ".tmp_source.zig:4:40: note: quota exceeded here"); } ////////////////////////////////////////////////////////////////////////////// diff --git a/test/self_hosted.zig b/test/self_hosted.zig index 1becd42e75..4513b06dd7 100644 --- a/test/self_hosted.zig +++ b/test/self_hosted.zig @@ -415,9 +415,7 @@ error err2; #attribute("test") fn fn_call_of_struct_field() { - if (call_struct_field(Foo {.ptr = a_func,}) != 13) { - unreachable{}; - } + assert(call_struct_field(Foo {.ptr = a_func,}) == 13); } struct Foo { @@ -911,3 +909,55 @@ struct MemberFnRand { r.seed } } + +#attribute("test") +fn static_function_evaluation() { + assert(statically_added_number == 3); +} +const statically_added_number = static_add(1, 2); +fn static_add(a: i32, b: i32) -> i32 { a + b } + + +#attribute("test") +fn statically_initalized_list() { + assert(static_point_list[0].x == 1); + assert(static_point_list[0].y == 2); + assert(static_point_list[1].x == 3); + assert(static_point_list[1].y == 4); +} +struct Point { + x: i32, + y: i32, +} +const static_point_list = []Point { make_point(1, 2), make_point(3, 4) }; +fn make_point(x: i32, y: i32) -> Point { + return Point { + .x = x, + .y = y, + }; +} + + +#attribute("test") +fn static_eval_recursive() { + assert(seventh_fib_number == 21); +} +const seventh_fib_number = fibbonaci(7); +fn fibbonaci(x: i32) -> i32 { + if (x <= 1) return 1; + return fibbonaci(x - 1) + fibbonaci(x - 2); +} + +#attribute("test") +fn static_eval_while() { + assert(static_eval_while_number == 1); +} +const static_eval_while_number = static_while_loop_1(); +fn static_while_loop_1() -> i32 { + return while_loop_2(); +} +fn static_while_loop_2() -> i32 { + while (true) { + return 1; + } +} -- cgit v1.2.3 From fcedc35551cc6b14756499414e47c33004de3be4 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 14 Apr 2016 10:39:03 -0700 Subject: fix crash with generic function and implicit cast --- src/ast_render.cpp | 8 ++++++-- src/parser.cpp | 6 ++++-- test/run_tests.cpp | 2 +- test/self_hosted.zig | 11 +++++++++++ 4 files changed, 22 insertions(+), 5 deletions(-) (limited to 'test/run_tests.cpp') diff --git a/src/ast_render.cpp b/src/ast_render.cpp index 59a287b886..6b88579b49 100644 --- a/src/ast_render.cpp +++ b/src/ast_render.cpp @@ -326,9 +326,9 @@ static void render_node(AstRender *ar, AstNode *node) { AstNode *statement = node->data.block.statements.at(i); print_indent(ar); render_node(ar, statement); + fprintf(ar->f, ";\n"); } ar->indent -= ar->indent_size; - fprintf(ar->f, "\n"); print_indent(ar); fprintf(ar->f, "}"); break; @@ -438,7 +438,11 @@ static void render_node(AstRender *ar, AstNode *node) { fprintf(ar->f, ")"); break; case NodeTypeArrayAccessExpr: - zig_panic("TODO"); + render_node(ar, node->data.array_access_expr.array_ref_expr); + fprintf(ar->f, "["); + render_node(ar, node->data.array_access_expr.subscript); + fprintf(ar->f, "]"); + break; case NodeTypeSliceExpr: zig_panic("TODO"); case NodeTypeFieldAccessExpr: diff --git a/src/parser.cpp b/src/parser.cpp index 650a7e614d..0bd2f57830 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -2927,6 +2927,7 @@ static void clone_subtree_list(ZigList *dest, ZigList *src dest->resize(src->length); for (int i = 0; i < src->length; i += 1) { dest->at(i) = ast_clone_subtree(src->at(i), next_node_index); + dest->at(i)->parent_field = &dest->at(i); } } @@ -2958,11 +2959,12 @@ AstNode *ast_clone_subtree(AstNode *old_node, uint32_t *next_node_index) { memcpy(new_node, old_node, sizeof(AstNode)); new_node->create_index = *next_node_index; *next_node_index += 1; + new_node->parent_field = nullptr; switch (new_node->type) { case NodeTypeRoot: - clone_subtree_list(&new_node->data.root.top_level_decls, &old_node->data.root.top_level_decls, - next_node_index); + clone_subtree_list(&new_node->data.root.top_level_decls, + &old_node->data.root.top_level_decls, next_node_index); break; case NodeTypeFnProto: clone_subtree_tld(&new_node->data.fn_proto.top_level_decl, &old_node->data.fn_proto.top_level_decl, diff --git a/test/run_tests.cpp b/test/run_tests.cpp index 461ee4172c..30fc1fdcf8 100644 --- a/test/run_tests.cpp +++ b/test/run_tests.cpp @@ -1667,7 +1667,7 @@ extern void (*fn_ptr)(void); )SOURCE", 2, "pub extern var fn_ptr: ?extern fn();", R"SOURCE(pub inline fn foo() { - (??fn_ptr)() + (??fn_ptr)(); })SOURCE"); diff --git a/test/self_hosted.zig b/test/self_hosted.zig index b36627855e..33b1834d96 100644 --- a/test/self_hosted.zig +++ b/test/self_hosted.zig @@ -975,3 +975,14 @@ pub fn vec3(x: f32, y: f32, z: f32) -> Vec3 { .data = []f32 { x, y, z, }, } } + + +#attribute("test") +fn generic_fn_with_implicit_cast() { + assert(get_first_byte(u8)([]u8 {13}) == 13); + assert(get_first_byte(u16)([]u16 {0, 13}) == 0); +} +fn get_byte(ptr: ?&u8) -> u8 {*??ptr} +fn get_first_byte(T: type)(mem: []T) -> u8 { + get_byte((&u8)(&mem[0])) +} -- cgit v1.2.3