# # Test of tracking of variable definedness # # Copyright © 2022-2024 Samuel Lidén Borell # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # func test_definedness_1(bool choice) -> bool { bool b = true return b } func test_definedness_2(bool choice) -> bool { var bool b b = true return b } func test_definedness_3(bool choice) -> bool { var bool b if choice { b = true } else { b = false } return b } func test_definedness_4(bool choice) -> bool { var bool b while true { b = false break } if choice { b = true } else { b = false } return b } func test_definedness_if1(bool choice, bool c2, bool c3) -> bool { var bool b if choice { b = true } else if not c2 { b = c3 } else { b = false } return b } func test_definedness_if2(bool choice, bool c2, bool c3) -> bool { var bool b if choice { return false } else if not c2 { b = c3 } else { b = false } return b } func test_definedness_if3(bool choice, bool c2, bool c3) -> bool { var bool b if choice { b = true } else if not c2 { return false } else { b = false } return b } func test_definedness_if4(bool choice, bool c2, bool c3) -> bool { var bool b if choice { b = true } else if not c2 { b = c3 } else { return false } return b } func test_definedness_if5(bool choice, int x) -> bool { var bool b if choice { b = true } else if x < 0 { if x == -3 { return false } else { b = (x == -1) } } else if x >= 10 { b = false if x == 11 { b = true } } else { int y = x+1 if y == 3 { b = true } else { return false } } return b } func test_definedness_if6(int choice, int x) -> int { var int i if choice < 4 { if choice == 1 { if x == 0 { i = 123 } else if x < 0 { i = -x } else { return -1 } } else if choice == 2 { return -2 } else { i = 789 } } else { i = choice } return i } func test_definedness_block(int choice, int x) -> int { var int i { { if x == 1 return 11 else if x == 2 { i = 2 } else return 0 } } return i } func test_definedness_goto1(int num, bool flag) -> int { var int a var int b if num == 1 { a = 1 goto other } else if num == 2 { a = 2 other: b = 20 } else { a = 3 b = 30 } if flag return b return a } func test_definedness_goto2(int num, bool flag) -> int { var int a var int b var int c if num == 1 { a = 1 b = 1 first: c = 10 } else if num == 2 { a = 2 other: b = 20 goto first } else if num == 3 { a = 3 goto other } else { a = 3 b = 30 goto first } if flag return b return a } func test_definedness_switch1(int choice) -> int { var int i switch choice { case 1: i = 123 case 2: i = 456 default: i = 789 } return i } func test_definedness_switch2(int choice, int x) -> int { var int i if choice < 4 { switch choice { case 1: if x == 0 { i = 111 } else if x < 0 { i = -x } else { i = 222 } case 2: i = 333 default: i = 444 } } else { i = choice } return i } func test_definedness_switch3(int choice, int x) -> int { var int i if choice < 4 { switch choice { case 1: if x == 0 { i = 123 } else if x < 0 { i = -x } else { return -1 } case 2: return -2 default: i = 789 } } else { i = choice } return i } func test_definedness_switch4(int choice, int x) -> int { var int i if choice < 4 { switch choice { case 1: switch x { case 10: i = 123 default: return -1 } case 2: return -2 default: i = 789 } } else { i = choice } return i } func test_definedness_switch5(int choice, int x) -> int { var int i if choice < 4 { switch choice { case 1: switch x { case 10: i = 123 default: return -1 } case 2: return -2 default: i = 789 } } else { return -2 } return i } func test_definedness_switch6(int x, int y) -> int { # This is simply a test of reference counting, that it does not go below 0 switch x { case 123: switch y { case 456: } default: } return 3 } func take_nonopt_param(ref ImplType non_opt) { } func test_definedness_nullability( ?ref ImplType opt_param, ?ref [3]byte opt_arr, int i) { var ref ImplType non_opt if opt_param != none { assert opt_param.x == 456 } if opt_param == none { # dummy } else { assert opt_param.x == 456 if i == 123 { goto not_none } } while opt_param != none { assert opt_param.x == 456 break } assert opt_param != none assert opt_param.x == 456 not_none: assert opt_param.x == 456 non_opt = opt_param take_nonopt_param(opt_param) # TODO boolean short-circuiting #if opt_arr != none and opt_arr[2] == 123 {} if opt_arr != none { assert opt_arr[2] == 789 # FIXME this generates IR with a strange DEREF # (dereferencing and storing the result to a DPTR) #assert (deref opt_arr)[2] == 789 } } func test_definedness_nullability_index(?ref usize indptr) -> byte { [3]byte arr = [11,22,33] if indptr != none { # TODO implement type detection of comparison operations # TODO require range check before accessing arrays #if deref indptr >= 0 and deref indptr < 3 { return arr[deref indptr] #} } return 0 } func definedness_testfunc(int x) -> int { return x * 111 } func take_nonopt_funcref(funcref(int x)->int f) { assert f(-1) == -11 } func test_definedness_nullability_funcref( ?funcref(int x)->int opt_f, funcref(int x)->int f, int i) -> int { var int r = 0 var funcref(int x)->int non_opt if opt_f != none { assert opt_f(1) == 11 r += 1 } if opt_f == none { # dummy } else { assert opt_f(2) == 22 r += 2 if i == 123 { r += 4 goto not_none } } while opt_f != none { r += 8 assert opt_f(3) == 33 break } assert opt_f != none assert opt_f(4) == 44 r += 16 not_none: assert opt_f(5) == 55 non_opt = opt_f take_nonopt_funcref(opt_f) non_opt = f r += 32 return opt_f(99) } func definedness_test() { assert test_definedness_1(false) assert test_definedness_1(true) assert test_definedness_2(false) assert test_definedness_2(true) assert not test_definedness_3(false) assert test_definedness_3(true) assert not test_definedness_4(false) assert test_definedness_4(true) assert not test_definedness_if1(false, false, false) assert test_definedness_if1(false, false, true) assert not test_definedness_if1(false, true, true) assert test_definedness_if1(true, false, false) assert not test_definedness_if2(false, false, false) assert test_definedness_if2(false, false, true) assert not test_definedness_if2(true, true, true) assert not test_definedness_if3(false, false, true) assert test_definedness_if3(true, false, false) assert test_definedness_if4(false, false, true) assert test_definedness_if4(true, false, false) assert not test_definedness_if5(false, -3) assert not test_definedness_if5(false, -2) assert test_definedness_if5(false, -1) assert not test_definedness_if5(false, 0) assert not test_definedness_if5(false, 1) assert test_definedness_if5(false, 2) assert not test_definedness_if5(false, 10) assert test_definedness_if5(false, 11) assert test_definedness_if5(true, 123) assert test_definedness_if6(0, -1) == 789 assert test_definedness_if6(1, -456) == 456 assert test_definedness_if6(1, 0) == 123 assert test_definedness_if6(1, 1) == -1 assert test_definedness_if6(2, 1) == -2 assert test_definedness_if6(5, 1) == 5 assert test_definedness_block(0, 1) == 11 assert test_definedness_block(0, 2) == 2 assert test_definedness_block(0, 3) == 0 assert test_definedness_goto1(1, false) == 1 assert test_definedness_goto1(1, true) == 20 assert test_definedness_goto1(2, false) == 2 assert test_definedness_goto1(2, true) == 20 assert test_definedness_goto1(3, false) == 3 assert test_definedness_goto1(3, true) == 30 assert test_definedness_goto2(1, false) == 1 assert test_definedness_goto2(2, false) == 2 assert test_definedness_goto2(2, true) == 20 assert test_definedness_goto2(3, false) == 3 assert test_definedness_goto2(3, true) == 20 assert test_definedness_goto2(4, true) == 30 assert test_definedness_switch1(1) == 123 assert test_definedness_switch1(2) == 456 assert test_definedness_switch1(-1) == 789 assert test_definedness_switch2(1, -5) == 5 assert test_definedness_switch2(1, 0) == 111 assert test_definedness_switch2(1, 1) == 222 assert test_definedness_switch2(2, 0) == 333 assert test_definedness_switch2(3, 0) == 444 assert test_definedness_switch2(4, -234) == 4 assert test_definedness_switch3(0, 0) == 789 assert test_definedness_switch3(1, -4) == 4 assert test_definedness_switch3(1, 0) == 123 assert test_definedness_switch3(1, 1) == -1 assert test_definedness_switch3(2, 1) == -2 assert test_definedness_switch3(3, 1) == 789 assert test_definedness_switch3(4, 321) == 4 assert test_definedness_switch4(0, 2) == 789 assert test_definedness_switch4(1, 10) == 123 assert test_definedness_switch4(1, 11) == -1 assert test_definedness_switch4(5, 11) == 5 assert test_definedness_switch5(1, 10) == 123 assert test_definedness_switch5(1, 11) == -1 assert test_definedness_switch5(2, 11) == -2 assert test_definedness_switch5(3, 11) == 789 assert test_definedness_switch5(11, 0) == -2 assert test_definedness_switch6(0, 0) == 3 assert test_definedness_switch6(123, 0) == 3 assert test_definedness_switch6(123, 456) == 3 # FIXME this test always freezes or fails #assert test_definedness_nullability(none, none, 1) assert test_definedness_nullability_index(none) == 0 var usize ind = 1 assert test_definedness_nullability_index(refto ind) == 22 ind = 2 assert test_definedness_nullability_index(refto ind) == 33 # TODO should the syntax use "refto" for functions? funcref (int x)->int r = definedness_testfunc assert test_definedness_nullability_funcref( none, definedness_testfunc, 123 ) == 99 assert test_definedness_nullability_funcref( definedness_testfunc, definedness_testfunc, 123 ) == 99 test_definedness_nullability_funcref( none, definedness_testfunc, 123 ) }