diff --git a/lib/std/io/formatter.c3 b/lib/std/io/formatter.c3 index 4c89d5ee1..dc408dc4a 100644 --- a/lib/std/io/formatter.c3 +++ b/lib/std/io/formatter.c3 @@ -146,10 +146,12 @@ fn usz? Formatter.out_str(&self, any arg) @private case VOID: return self.out_substr("void"); case FAULT: - return self.out_substr((*(fault*)arg.ptr).nameof); + fault f = *(fault*)arg.ptr; + return self.out_substr(f ? f.nameof : "(nofault)"); case INTERFACE: case ANY: - return self.out_str(*(any*)arg); + any a = *(any*)arg; + return a ? self.out_str(a) : self.out_substr("(null)"); case OPTIONAL: unreachable(); case SIGNED_INT: diff --git a/releasenotes.md b/releasenotes.md index b049ca9a1..e480257d8 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -20,6 +20,7 @@ - Parsing difference between "0x00." and "0X00." literals #2371 - Fixed bug generating `$c += 1` when `$c` was derived from a pointer but behind a cast. - Compiler segfault when using bitwise not on number literal cast to bitstruct #2373. +- Formatter did not properly handle "null" for any, and null for empty faults. #2375 ### Stdlib changes - Add `==` to `Pair`, `Triple` and TzDateTime. Add print to `Pair` and `Triple`. diff --git a/test/unit/regression/formatting.c3 b/test/unit/regression/formatting.c3 new file mode 100644 index 000000000..89300e509 --- /dev/null +++ b/test/unit/regression/formatting.c3 @@ -0,0 +1,30 @@ +module format_test; +import std::io; + +interface Decl +{ +} + +struct TestS (Decl, Printable) +{ + int a; +} +fn usz? TestS.to_format(&self, Formatter* formatter) @dynamic => formatter.printf("[%d]", self.a); + +faultdef DERP; + +fn void various_cornercases() @test +{ + TestS a = {100}; + Decl z = &a; + test::eq(string::tformat("%s", z), "[100]"); + + fault p; fault o = DERP; + test::eq(string::tformat("%s|%s", p, o), "(nofault)|format_test::DERP"); + + Decl y; + test::eq(string::tformat("%s", y), "(null)"); + + int* x; + test::eq(string::tformat("%s", x), "0x0"); +}