harec

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit 38de3d690073d5d4bac8695b747179097beaa1b7
parent 20db8aa13ac26b27e7a60286dc283b65da24e14e
Author: Eyal Sawady <ecs@d2evs.net>
Date:   Fri, 25 Feb 2022 16:45:23 +0000

Add tests for flexible constants

Signed-off-by: Eyal Sawady <ecs@d2evs.net>

Diffstat:
Mtests/00-constants.ha | 139+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mtests/30-reduction.c | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 195 insertions(+), 0 deletions(-)

diff --git a/tests/00-constants.ha b/tests/00-constants.ha @@ -1,3 +1,137 @@ +use rt; + +type my_enum = enum u8 { + FOO, +}; + +fn assignment() void = { + let i = 0i8; + let u = 0u64; + let f = 0.0f64; + let r = 'a'; + let e = my_enum::FOO; + + // There are five cases that need to be tested for tagged unions: + // - The default type for the constant is a member of the union + // - A single non-default type the constant could assume is a member of + // the union + // - The default type for the constant along with at least one other + // type the constant could assume are both members of the union + // - At least two types the constant could assume are members of the + // union, and the default type isn't a member of the union + // - None of the types the constant could assume are members of the + // union + // All but the fourth and fifth case are valid, and the invalid cases + // should error out gracefully. + let itu1: (int | void) = void; + let itu2: (u64 | void) = void; + let itu3: (int | u64 | void) = void; + let ftu1: (f64 | void) = void; + let ftu2: (f32 | void) = void; + let ftu3: (f32 | f64 | void) = void; + let rtu1: (rune | void) = void; + let rtu2: (u64 | void) = void; + let rtu3: (rune | u64 | void) = void; + + i = 127; + assert(rt::compile("export fn main() void = { let i = 0i8; i = 128; };") != 0); + u = 18446744073709551615; + assert(rt::compile("export fn main() void = { let u = 0u32; u = 4294967296; };") != 0); + assert(rt::compile("export fn main() void = { let f = 0.0f64; f = 0; };") != 0); + assert(rt::compile("export fn main() void = { let r = 'a'; r = 0; };") != 0); + e = 0; + assert(rt::compile("type my_enum = enum u8 { FOO }; export fn main() void = { let e: my_enum = my_enum::FOO; e = 256; };") != 0); + assert(rt::compile("export fn main() void = { let p: nullable *void = null; p = 0; };") != 0); + assert(rt::compile("export fn main() void = { let b = false; b = 0; };") != 0); + assert(rt::compile("export fn main() void = { let n = null; n = 0; };") != 0); + assert(rt::compile("export fn main() void = { let s: struct { i: int } = struct { i: int = 0 }; s = 0; };") != 0); + assert(rt::compile("export fn main() void = { let t = (0, 1); t = 0; };") != 0); + assert(rt::compile("export fn main() void = { let a = [0, 1]; a = 0; };") != 0); + assert(rt::compile("export fn main() void = { let s = \"\"; s = 0; };") != 0); + itu1 = 0; + itu2 = 0; + itu3 = 0; + assert(rt::compile("export fn main() void = { let itu4: (u32 | u64 | void) = void; itu4 = 0; };") != 0); + assert(rt::compile("export fn main() void = { let itu5: (str | void) = void; itu5 = 0; };") != 0); + + assert(rt::compile("export fn main() void = { let i = 0i8; i = 0.0; };") != 0); + assert(rt::compile("export fn main() void = { let u = 0u8; u = 0.0; };") != 0); + f = 0.0; + assert(rt::compile("export fn main() void = { let r = 'a'; r = 0.0; };") != 0); + assert(rt::compile("type my_enum = enum u8 { FOO }; export fn main() void = { let e: my_enum = my_enum::FOO; e = 0.0; };") != 0); + assert(rt::compile("export fn main() void = { let p: nullable *void = null; p = 0.0; };") != 0); + assert(rt::compile("export fn main() void = { let b = false; b = 0.0; };") != 0); + assert(rt::compile("export fn main() void = { let n = null; n = 0.0; };") != 0); + assert(rt::compile("export fn main() void = { let s: struct { i: int } = struct { i: int = 0 }; s = 0.0; };") != 0); + assert(rt::compile("export fn main() void = { let t = (0, 1); t = 0.0; };") != 0); + assert(rt::compile("export fn main() void = { let a = [0, 1]; a = 0.0; };") != 0); + assert(rt::compile("export fn main() void = { let s = ""; s = 0.0; };") != 0); + ftu1 = 0.0; + ftu2 = 0.0; + ftu3 = 0.0; + assert(rt::compile("type my_f32 = f32; export fn main() void = { let ftu4: (f32 | my_f32 | void) = void; ftu4 = 0.0; };") != 0); + assert(rt::compile("export fn main() void = { let ftu5: (str | void) = void; ftu5 = 0.0; };") != 0); + + i = 'a'; + u = 'a'; + assert(rt::compile("export fn main() void = { let f = 0.0f64; f = 'a'; };") != 0); + r = 'a'; + e = 'a'; + assert(rt::compile("export fn main() void = { let p: nullable *void = null; p = 'a'; };") != 0); + assert(rt::compile("export fn main() void = { let b = false; b = 'a'; };") != 0); + assert(rt::compile("export fn main() void = { let n = null; n = 'a'; };") != 0); + assert(rt::compile("export fn main() void = { let s: struct { i: int } = struct { i: int = 0 }; s = 'a'; };") != 0); + assert(rt::compile("export fn main() void = { let t = (0, 1); t = 'a'; };") != 0); + assert(rt::compile("export fn main() void = { let a = [0, 1]; a = 'a'; };") != 0); + assert(rt::compile("export fn main() void = { let s = ""; s = 'a'; };") != 0); + rtu1 = 'a'; + rtu2 = 'a'; + rtu3 = 'a'; + assert(rt::compile("export fn main() void = { let rtu4: (u32 | u64 | void) = void; rtu4 = 'a'; };") != 0); + assert(rt::compile("export fn main() void = { let rtu5: (str | void) = void; rtu5 = 'a'; };") != 0); +}; + +fn aggregates() void = { + // Pointers + + // Kinda hacky way to verify that something has the expected type + // The variables are necessary in order to avoid type hints, which would + // avoid verifying that constants are lowered when entering aggregate + // types + let maxiptr = if (true) alloc(2147483647) else void; + free(maxiptr as *int); + let miniptr = if (true) alloc(-2147483648) else void; + free(miniptr as *int); + let smalli64ptr = if (true) alloc(2147483648) else void; + free(smalli64ptr as *i64); + let negi64ptr = if (true) alloc(-2147483649) else void; + free(negi64ptr as *i64); + let maxi64ptr = if (true) alloc(9223372036854775807) else void; + free(maxi64ptr as *i64); + // -9223372036854775808 can't be made to work without lots of hacks + let mini64ptr = if (true) alloc(-9223372036854775807) else void; + free(mini64ptr as *i64); + let fptr = if (true) alloc(0.0) else void; + free(fptr as *f64); + let rptr = if (true) alloc('a') else void; + free(rptr as *rune); + + // Tuples + + // The edge cases of the iconst lowering algorithm were already tested + // above, and tuple items can't affect each other, so this suffices + let tuple = if (true) (2147483647, 0.0, 'a') else void; + tuple as (int, f64, rune); + + // Arrays + let iarr = if (true) [0, 1, 2] else void; + iarr as [3]int; + let uarr = if (true) [0u8, 1, 2] else void; + uarr as [3]u8; + let u2arr = if (true) [0, 1u8, 2] else void; + u2arr as [3]u8; +}; + export fn main() void = { let i1 = 13, i2 = 13i, i3 = 13i8, i4 = 13i16, i5 = 13i32, i6 = 13i64; let u1 = 13u, u2 = 13z, u3 = 13u8, u4 = 13u16, u5 = 13u32, u6 = 13u64; @@ -10,4 +144,9 @@ export fn main() void = { r15 = '\U12345678'; let f1 = 1.0, f2 = 1f32, f3 = 1.0e2, f4 = 1.0f64; let f5 = 1.23e+45, f6 = 9.87e-65, f7 = 1e-7, f8 = 5.0e-324; + + // The interaction between constants and result type reduction is tested + // in 30-reduction.c + assignment(); + aggregates(); }; diff --git a/tests/30-reduction.c b/tests/30-reduction.c @@ -129,4 +129,60 @@ int main(void) { test(&ctx, "", "if (true) null " "else void"); + + // However, constants behave differently in if vs switch/match + + test(&ctx, "int", "if (true) 0 else if (true) 1 else 2"); + test(&ctx, "(int | i64)", "if (true) 0 else 9223372036854775807"); + test(&ctx, "(int | size)", "if (true) 0 else 0z"); + test(&ctx, "(int | void)", "if (true) 0 else void"); + + test(&ctx, "int", + "switch (0) { " + "case 0 => " + " yield 0; " + "case 1 => " + " yield 1; " + "case => " + " yield 2; " + "};"); + test(&ctx, "(int | i64)", + "switch (0) { " + "case 0 => " + " yield 0; " + "case => " + " yield 9223372036854775807; " + "};"); + test(&ctx, "(int | size)", + "switch (0) { " + "case 0 => " + " yield 0; " + "case => " + " yield 0z; " + "};"); + test(&ctx, "(int | void)", + "switch (0) { " + "case 0 => " + " yield 0; " + "case => " + " yield; " + "};"); + test(&ctx, "(int | size | u32)", + "switch (0) { " + "case 0 => " + " yield 0; " + "case 1 => " + " yield 1z; " + "case => " + " yield 2u32; " + "};"); + test(&ctx, "(int | i64)", + "switch (0) { " + "case 0 => " + " yield 0; " + "case 1 => " + " yield 1i; " + "case => " + " yield 9223372036854775807; " + "};"); }