diff --git a/examples/tests/invalid/stringify.test.w b/examples/tests/invalid/stringify.test.w index fc7ff61dd3d..9f2231e8b3f 100644 --- a/examples/tests/invalid/stringify.test.w +++ b/examples/tests/invalid/stringify.test.w @@ -1,11 +1,21 @@ class B {} let b = new B(); +struct Foo { + bar: B; + baz: str; +} + +let foo: Foo = {bar: b, baz: "hello"}; + log("hello {b}"); -// ^ Error: expected type to be stringable +// ^ Expected type to be "stringable", but got "B" instead let x: str? = nil; log("{x}"); -// ^ Error: expected type to be stringable +// ^ Expected type to be "stringable", but got "str?" instead log(b); -// ^ Error: expected type to be stringable +// ^ Expected type to be "stringable", but got "B" instead + +log(foo); +// ^ Expected type to be "stringable", but got "Foo" instead diff --git a/examples/tests/valid/stringify.test.w b/examples/tests/valid/stringify.test.w index 5cfc5a75401..b97f1a62d98 100644 --- a/examples/tests/valid/stringify.test.w +++ b/examples/tests/valid/stringify.test.w @@ -1,8 +1,14 @@ enum MyEnum { A, B, C } +struct Foo { + bar: str; +} +let foo = Foo { bar: "hello" }; + // If a value's type is stringable, it can be passed directly to the "log" function log("my string"); log(42); log(true); log(Json { "cool": "beans" }); log(MyEnum.A); +log(foo); diff --git a/libs/wingc/src/type_check.rs b/libs/wingc/src/type_check.rs index 4b9d709ee30..0bd844934f7 100644 --- a/libs/wingc/src/type_check.rs +++ b/libs/wingc/src/type_check.rs @@ -775,6 +775,7 @@ impl Subtype for Type { (Self::Json(_), Self::Json(_)) => true, (Self::MutJson, Self::Stringable) => true, (Self::Enum(_), Self::Stringable) => true, + (Self::Struct(s), Self::Stringable) => s.fields(true).map(|(_, v)| v.type_).all(|t| t.is_stringable()), _ => false, } } @@ -1127,6 +1128,14 @@ impl TypeRef { matches!(**self, Type::Struct(_)) } + pub fn is_stringable_struct(&self) -> bool { + if let Type::Struct(ref s) = **self { + s.fields(true).map(|(_, v)| v.type_).all(|t| t.is_stringable()) + } else { + false + } + } + pub fn is_map(&self) -> bool { matches!(**self, Type::Map(_) | Type::MutMap(_)) } @@ -1169,7 +1178,7 @@ impl TypeRef { matches!( **self, Type::String | Type::Number | Type::Boolean | Type::Json(_) | Type::MutJson | Type::Enum(_) | Type::Anything - ) + ) || self.is_stringable_struct() } /// If this is a function and its last argument is a struct, return that struct. diff --git a/tools/hangar/__snapshots__/invalid.ts.snap b/tools/hangar/__snapshots__/invalid.ts.snap index f4fbbac5d47..3b58593b615 100644 --- a/tools/hangar/__snapshots__/invalid.ts.snap +++ b/tools/hangar/__snapshots__/invalid.ts.snap @@ -4595,31 +4595,40 @@ Duration " exports[`stringify.test.w 1`] = ` "error: Expected type to be "stringable", but got "B" instead - --> ../../../examples/tests/invalid/stringify.test.w:3:13 - | -3 | log("hello {b}"); - | ^ - | - = hint: str, num, bool, json, and enums are stringable + --> ../../../examples/tests/invalid/stringify.test.w:10:13 + | +10 | log("hello {b}"); + | ^ + | + = hint: str, num, bool, json, and enums are stringable error: Expected type to be "stringable", but got "str?" instead - --> ../../../examples/tests/invalid/stringify.test.w:7:7 - | -7 | log("{x}"); - | ^ - | - = hint: str? is an optional, try unwrapping it with 'x ?? "nil"' or 'x!' + --> ../../../examples/tests/invalid/stringify.test.w:14:7 + | +14 | log("{x}"); + | ^ + | + = hint: str? is an optional, try unwrapping it with 'x ?? "nil"' or 'x!' error: Expected type to be "stringable", but got "B" instead - --> ../../../examples/tests/invalid/stringify.test.w:10:5 + --> ../../../examples/tests/invalid/stringify.test.w:17:5 | -10 | log(b); +17 | log(b); | ^ | = hint: str, num, bool, json, and enums are stringable + +error: Expected type to be "stringable", but got "Foo" instead + --> ../../../examples/tests/invalid/stringify.test.w:20:5 + | +20 | log(foo); + | ^^^ + | + = hint: str, num, bool, json, and enums are stringable + Tests 1 failed (1) Snapshots 1 skipped Test Files 1 failed (1) diff --git a/tools/hangar/__snapshots__/test_corpus/valid/stringify.test.w_compile_tf-aws.md b/tools/hangar/__snapshots__/test_corpus/valid/stringify.test.w_compile_tf-aws.md index 532d73b8bc8..e720fc368b0 100644 --- a/tools/hangar/__snapshots__/test_corpus/valid/stringify.test.w_compile_tf-aws.md +++ b/tools/hangar/__snapshots__/test_corpus/valid/stringify.test.w_compile_tf-aws.md @@ -44,11 +44,13 @@ class $Root extends $stdlib.std.Resource { return tmp; })({}) ; + const foo = ({"bar": "hello"}); console.log("my string"); console.log(42); console.log(true); console.log(({"cool": "beans"})); console.log(MyEnum.A); + console.log(foo); } } const $APP = $PlatformManager.createApp({ outdir: $outdir, name: "stringify.test", rootConstruct: $Root, isTestEnvironment: $wing_is_test, entrypointDir: process.env['WING_SOURCE_DIR'], rootId: process.env['WING_ROOT_ID'] }); diff --git a/tools/hangar/__snapshots__/test_corpus/valid/stringify.test.w_test_sim.md b/tools/hangar/__snapshots__/test_corpus/valid/stringify.test.w_test_sim.md index 63c636c9625..e8cd4b88a4d 100644 --- a/tools/hangar/__snapshots__/test_corpus/valid/stringify.test.w_test_sim.md +++ b/tools/hangar/__snapshots__/test_corpus/valid/stringify.test.w_test_sim.md @@ -7,6 +7,7 @@ my string true { cool: 'beans' } A +{ bar: 'hello' } pass ─ stringify.test.wsim (no tests) Tests 1 passed (1)