Skip to content

Commit 93aec85

Browse files
authored
fix: type unions in variadic position leads to invalid code-gen (#3722)
The code-gen for type unions was incorrect, as the value is typically array-typed, and the generated code hence needs to treat the value as such.
1 parent c73c2ee commit 93aec85

File tree

14 files changed

+644
-286
lines changed

14 files changed

+644
-286
lines changed

packages/@jsii/dotnet-runtime-test/test/Amazon.JSII.Runtime.IntegrationTests/TypeCheckingTests.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,5 +97,18 @@ public void NestedUnion()
9797
}));
9898
Assert.Equal("Expected argument unionProperty[0][\"bad\"] to be one of: Amazon.JSII.Tests.CalculatorNamespace.IStructA, Amazon.JSII.Tests.CalculatorNamespace.IStructB; received System.String (Parameter 'unionProperty')", exception3.Message);
9999
}
100+
101+
[Fact(DisplayName = Prefix + nameof(Variadic))]
102+
public void Variadic()
103+
{
104+
var exception1 = Assert.Throws<System.ArgumentException>(() =>
105+
new VariadicTypeUnion(
106+
new StructA{RequiredString = "present"},
107+
1337.42
108+
));
109+
Assert.Equal("Expected argument union[1] to be one of: Amazon.JSII.Tests.CalculatorNamespace.IStructA, Amazon.JSII.Tests.CalculatorNamespace.IStructB; received System.Double (Parameter 'union')", exception1.Message);
110+
111+
Assert.NotNull(new VariadicTypeUnion());
112+
}
100113
}
101114
}

packages/@jsii/go-runtime-test/project/runtime_type_checking_test.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,16 @@ func TestNestedUnion(t *testing.T) {
7979
}()
8080
}
8181

82+
func TestVariadic(t *testing.T) {
83+
func() {
84+
defer expectPanic(t, "parameter union[1] must be one of the allowed types: *StructA, *StructB; received 1337.42 (a float64)")
85+
jsiicalc.NewVariadicTypeUnion(jsiicalc.StructA{RequiredString: jsii.String("present")}, 1337.42)
86+
}()
87+
88+
// Should not raise
89+
jsiicalc.NewVariadicTypeUnion()
90+
}
91+
8292
func expectPanic(t *testing.T, expected string) {
8393
if err := recover(); err != nil {
8494
actual := fmt.Sprintf("%v", err)

packages/@jsii/python-runtime/tests/test_runtime_type_checking.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,3 +126,25 @@ def test_anonymous_object(self):
126126

127127
iface = jsii_calc.anonymous.UseOptions.provide("A")
128128
assert jsii_calc.anonymous.UseOptions.consume(iface) == "A"
129+
130+
def test_nested_union(self):
131+
with pytest.raises(
132+
TypeError,
133+
match=re.escape(
134+
"type of argument union_property[0] must be one of (Mapping[str, Union[jsii_calc.StructA, Dict[str, Any], jsii_calc.StructB]], Sequence[Union[jsii_calc.StructA, Dict[str, Any], jsii_calc.StructB]]); got float instead"
135+
),
136+
):
137+
jsii_calc.ClassWithNestedUnion([1337.42]) # type:ignore
138+
139+
def test_variadic(self):
140+
with pytest.raises(
141+
TypeError,
142+
match=re.escape(
143+
"type of argument union[1] must be one of (jsii_calc.StructA, jsii_calc.StructB); got float instead"
144+
),
145+
):
146+
jsii_calc.VariadicTypeUnion(
147+
jsii_calc.StructA(required_string="present"), 1337.42 # type:ignore
148+
)
149+
150+
jsii_calc.VariadicTypeUnion()

packages/jsii-calc/lib/compliance.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3082,3 +3082,11 @@ export class ClassWithNestedUnion {
30823082
>,
30833083
) {}
30843084
}
3085+
3086+
export class VariadicTypeUnion {
3087+
public union: Array<StructA | StructB>;
3088+
3089+
public constructor(...union: Array<StructA | StructB>) {
3090+
this.union = union;
3091+
}
3092+
}

packages/jsii-calc/test/assembly.jsii

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15428,6 +15428,77 @@
1542815428
"name": "VariadicMethod",
1542915429
"symbolId": "lib/compliance:VariadicMethod"
1543015430
},
15431+
"jsii-calc.VariadicTypeUnion": {
15432+
"assembly": "jsii-calc",
15433+
"docs": {
15434+
"stability": "stable"
15435+
},
15436+
"fqn": "jsii-calc.VariadicTypeUnion",
15437+
"initializer": {
15438+
"docs": {
15439+
"stability": "stable"
15440+
},
15441+
"locationInModule": {
15442+
"filename": "lib/compliance.ts",
15443+
"line": 3089
15444+
},
15445+
"parameters": [
15446+
{
15447+
"name": "union",
15448+
"type": {
15449+
"union": {
15450+
"types": [
15451+
{
15452+
"fqn": "jsii-calc.StructA"
15453+
},
15454+
{
15455+
"fqn": "jsii-calc.StructB"
15456+
}
15457+
]
15458+
}
15459+
},
15460+
"variadic": true
15461+
}
15462+
],
15463+
"variadic": true
15464+
},
15465+
"kind": "class",
15466+
"locationInModule": {
15467+
"filename": "lib/compliance.ts",
15468+
"line": 3086
15469+
},
15470+
"name": "VariadicTypeUnion",
15471+
"properties": [
15472+
{
15473+
"docs": {
15474+
"stability": "stable"
15475+
},
15476+
"locationInModule": {
15477+
"filename": "lib/compliance.ts",
15478+
"line": 3087
15479+
},
15480+
"name": "union",
15481+
"type": {
15482+
"collection": {
15483+
"elementtype": {
15484+
"union": {
15485+
"types": [
15486+
{
15487+
"fqn": "jsii-calc.StructA"
15488+
},
15489+
{
15490+
"fqn": "jsii-calc.StructB"
15491+
}
15492+
]
15493+
}
15494+
},
15495+
"kind": "array"
15496+
}
15497+
}
15498+
}
15499+
],
15500+
"symbolId": "lib/compliance:VariadicTypeUnion"
15501+
},
1543115502
"jsii-calc.VirtualMethodPlayground": {
1543215503
"assembly": "jsii-calc",
1543315504
"docs": {
@@ -18131,5 +18202,5 @@
1813118202
}
1813218203
},
1813318204
"version": "3.20.120",
18134-
"fingerprint": "LBLJQQycukWu6zWQmp2/IbKS/Sfd+4e2zWrX+1KA+Aw="
18205+
"fingerprint": "Ze43eowG9ImRufT3MQ8yO+bW8JzOQlZIYtFsjpc960E="
1813518206
}

packages/jsii-pacmak/lib/targets/dotnet/runtime-type-checking.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { CollectionKind } from '@jsii/spec';
12
import { CodeMaker } from 'codemaker';
23
import { createHash } from 'crypto';
34
import { Parameter, TypeReference } from 'jsii-reflect';
@@ -27,7 +28,14 @@ export class ParameterValidator {
2728
argName,
2829
expr,
2930
`${noMangle ? '' : 'argument '}{${argName}}`,
30-
param.type,
31+
param.variadic
32+
? new TypeReference(param.system, {
33+
collection: {
34+
kind: CollectionKind.Array,
35+
elementtype: param.type.spec!,
36+
},
37+
})
38+
: param.type,
3139
param.optional,
3240
);
3341
if (validation) {

packages/jsii-pacmak/lib/targets/go/runtime/runtime-type-checking.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,13 +83,15 @@ export class ParameterValidator {
8383
const descr = `parameter ${param.name}`;
8484

8585
const validations = new Array<Validation>();
86-
if (!param.isOptional) {
86+
if (!param.isOptional && !param.isVariadic) {
8787
validations.push(Validation.nullCheck(expr, descr, param.reference));
8888
}
8989
const validation = Validation.forTypeMap(
9090
expr,
9191
descr,
92-
param.reference.typeMap,
92+
param.isVariadic
93+
? { type: 'array', value: param.reference }
94+
: param.reference.typeMap,
9395
);
9496
if (validation) {
9597
validations.push(validation);
@@ -144,7 +146,9 @@ export class ParameterValidator {
144146

145147
public emitCall(code: CodeMaker): void {
146148
const recv = this.receiver?.name ? `${this.receiver.name}.` : '';
147-
const params = this.parameters.map((p) => p.name).join(', ');
149+
const params = this.parameters
150+
.map((p) => (p.isVariadic ? `&${p.name}` : p.name))
151+
.join(', ');
148152

149153
code.openBlock(`if err := ${recv}${this.name}(${params}); err != nil`);
150154
code.line(`panic(err)`);
@@ -162,7 +166,7 @@ export class ParameterValidator {
162166
}${this.name}(${this.parameters
163167
.map((p) =>
164168
p.isVariadic
165-
? `${p.name} []${p.reference.scopedReference(scope)}`
169+
? `${p.name} *[]${p.reference.scopedReference(scope)}`
166170
: p.toString(),
167171
)
168172
.join(', ')}) error`,

packages/jsii-pacmak/test/generated-code/__snapshots__/target-dotnet.test.js.snap

Lines changed: 118 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)