Skip to content

Commit 0314c4a

Browse files
committed
fix(44639): Fix emit for optional chain with type assertions
1 parent a15030f commit 0314c4a

8 files changed

+218
-4
lines changed

src/compiler/transformers/es2020.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -122,11 +122,11 @@ namespace ts {
122122

123123
function visitOptionalExpression(node: OptionalChain, captureThisArg: boolean, isDelete: boolean): Expression {
124124
const { expression, chain } = flattenChain(node);
125-
const left = visitNonOptionalExpression(expression, isCallChain(chain[0]), /*isDelete*/ false);
125+
const left = visitNonOptionalExpression(skipPartiallyEmittedExpressions(expression), isCallChain(chain[0]), /*isDelete*/ false);
126126
const leftThisArg = isSyntheticReference(left) ? left.thisArg : undefined;
127-
let leftExpression = isSyntheticReference(left) ? left.expression : left;
128-
let capturedLeft: Expression = leftExpression;
129-
if (!isSimpleCopiableExpression(leftExpression)) {
127+
let capturedLeft = isSyntheticReference(left) ? left.expression : left;
128+
let leftExpression = factory.restoreOuterExpressions(expression, capturedLeft, OuterExpressionKinds.PartiallyEmittedExpressions);
129+
if (!isSimpleCopiableExpression(capturedLeft)) {
130130
capturedLeft = factory.createTempVariable(hoistVariableDeclaration);
131131
leftExpression = factory.createAssignment(capturedLeft, leftExpression);
132132
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//// [optionalChainingInTypeAssertions.ts]
2+
class Foo {
3+
m() {}
4+
}
5+
6+
const foo = new Foo();
7+
8+
(foo.m as any)?.();
9+
(<any>foo.m)?.();
10+
11+
/*a1*/(/*a2*/foo.m as any/*a3*/)/*a4*/?.();
12+
/*b1*/(/*b2*/<any>foo.m/*b3*/)/*b4*/?.();
13+
14+
15+
//// [optionalChainingInTypeAssertions.js]
16+
var _a, _b, _c, _d;
17+
class Foo {
18+
m() { }
19+
}
20+
const foo = new Foo();
21+
(_a = foo.m) === null || _a === void 0 ? void 0 : _a.call(foo);
22+
(_b = foo.m) === null || _b === void 0 ? void 0 : _b.call(foo);
23+
/*a1*/ (_c = foo.m /*a3*/ /*a4*/) === null || _c === void 0 ? void 0 : _c.call(/*a2*/ foo);
24+
/*b1*/ (_d = foo.m /*b3*/ /*b4*/) === null || _d === void 0 ? void 0 : _d.call(foo);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
=== tests/cases/conformance/expressions/optionalChaining/optionalChainingInTypeAssertions.ts ===
2+
class Foo {
3+
>Foo : Symbol(Foo, Decl(optionalChainingInTypeAssertions.ts, 0, 0))
4+
5+
m() {}
6+
>m : Symbol(Foo.m, Decl(optionalChainingInTypeAssertions.ts, 0, 11))
7+
}
8+
9+
const foo = new Foo();
10+
>foo : Symbol(foo, Decl(optionalChainingInTypeAssertions.ts, 4, 5))
11+
>Foo : Symbol(Foo, Decl(optionalChainingInTypeAssertions.ts, 0, 0))
12+
13+
(foo.m as any)?.();
14+
>foo.m : Symbol(Foo.m, Decl(optionalChainingInTypeAssertions.ts, 0, 11))
15+
>foo : Symbol(foo, Decl(optionalChainingInTypeAssertions.ts, 4, 5))
16+
>m : Symbol(Foo.m, Decl(optionalChainingInTypeAssertions.ts, 0, 11))
17+
18+
(<any>foo.m)?.();
19+
>foo.m : Symbol(Foo.m, Decl(optionalChainingInTypeAssertions.ts, 0, 11))
20+
>foo : Symbol(foo, Decl(optionalChainingInTypeAssertions.ts, 4, 5))
21+
>m : Symbol(Foo.m, Decl(optionalChainingInTypeAssertions.ts, 0, 11))
22+
23+
/*a1*/(/*a2*/foo.m as any/*a3*/)/*a4*/?.();
24+
>foo.m : Symbol(Foo.m, Decl(optionalChainingInTypeAssertions.ts, 0, 11))
25+
>foo : Symbol(foo, Decl(optionalChainingInTypeAssertions.ts, 4, 5))
26+
>m : Symbol(Foo.m, Decl(optionalChainingInTypeAssertions.ts, 0, 11))
27+
28+
/*b1*/(/*b2*/<any>foo.m/*b3*/)/*b4*/?.();
29+
>foo.m : Symbol(Foo.m, Decl(optionalChainingInTypeAssertions.ts, 0, 11))
30+
>foo : Symbol(foo, Decl(optionalChainingInTypeAssertions.ts, 4, 5))
31+
>m : Symbol(Foo.m, Decl(optionalChainingInTypeAssertions.ts, 0, 11))
32+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
=== tests/cases/conformance/expressions/optionalChaining/optionalChainingInTypeAssertions.ts ===
2+
class Foo {
3+
>Foo : Foo
4+
5+
m() {}
6+
>m : () => void
7+
}
8+
9+
const foo = new Foo();
10+
>foo : Foo
11+
>new Foo() : Foo
12+
>Foo : typeof Foo
13+
14+
(foo.m as any)?.();
15+
>(foo.m as any)?.() : any
16+
>(foo.m as any) : any
17+
>foo.m as any : any
18+
>foo.m : () => void
19+
>foo : Foo
20+
>m : () => void
21+
22+
(<any>foo.m)?.();
23+
>(<any>foo.m)?.() : any
24+
>(<any>foo.m) : any
25+
><any>foo.m : any
26+
>foo.m : () => void
27+
>foo : Foo
28+
>m : () => void
29+
30+
/*a1*/(/*a2*/foo.m as any/*a3*/)/*a4*/?.();
31+
>(/*a2*/foo.m as any/*a3*/)/*a4*/?.() : any
32+
>(/*a2*/foo.m as any/*a3*/) : any
33+
>foo.m as any : any
34+
>foo.m : () => void
35+
>foo : Foo
36+
>m : () => void
37+
38+
/*b1*/(/*b2*/<any>foo.m/*b3*/)/*b4*/?.();
39+
>(/*b2*/<any>foo.m/*b3*/)/*b4*/?.() : any
40+
>(/*b2*/<any>foo.m/*b3*/) : any
41+
><any>foo.m : any
42+
>foo.m : () => void
43+
>foo : Foo
44+
>m : () => void
45+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//// [optionalChainingInTypeAssertions.ts]
2+
class Foo {
3+
m() {}
4+
}
5+
6+
const foo = new Foo();
7+
8+
(foo.m as any)?.();
9+
(<any>foo.m)?.();
10+
11+
/*a1*/(/*a2*/foo.m as any/*a3*/)/*a4*/?.();
12+
/*b1*/(/*b2*/<any>foo.m/*b3*/)/*b4*/?.();
13+
14+
15+
//// [optionalChainingInTypeAssertions.js]
16+
class Foo {
17+
m() { }
18+
}
19+
const foo = new Foo();
20+
foo.m?.();
21+
foo.m?.();
22+
/*a1*/ foo.m /*a3*/ /*a4*/?.();
23+
/*b1*/ foo.m /*b3*/ /*b4*/?.();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
=== tests/cases/conformance/expressions/optionalChaining/optionalChainingInTypeAssertions.ts ===
2+
class Foo {
3+
>Foo : Symbol(Foo, Decl(optionalChainingInTypeAssertions.ts, 0, 0))
4+
5+
m() {}
6+
>m : Symbol(Foo.m, Decl(optionalChainingInTypeAssertions.ts, 0, 11))
7+
}
8+
9+
const foo = new Foo();
10+
>foo : Symbol(foo, Decl(optionalChainingInTypeAssertions.ts, 4, 5))
11+
>Foo : Symbol(Foo, Decl(optionalChainingInTypeAssertions.ts, 0, 0))
12+
13+
(foo.m as any)?.();
14+
>foo.m : Symbol(Foo.m, Decl(optionalChainingInTypeAssertions.ts, 0, 11))
15+
>foo : Symbol(foo, Decl(optionalChainingInTypeAssertions.ts, 4, 5))
16+
>m : Symbol(Foo.m, Decl(optionalChainingInTypeAssertions.ts, 0, 11))
17+
18+
(<any>foo.m)?.();
19+
>foo.m : Symbol(Foo.m, Decl(optionalChainingInTypeAssertions.ts, 0, 11))
20+
>foo : Symbol(foo, Decl(optionalChainingInTypeAssertions.ts, 4, 5))
21+
>m : Symbol(Foo.m, Decl(optionalChainingInTypeAssertions.ts, 0, 11))
22+
23+
/*a1*/(/*a2*/foo.m as any/*a3*/)/*a4*/?.();
24+
>foo.m : Symbol(Foo.m, Decl(optionalChainingInTypeAssertions.ts, 0, 11))
25+
>foo : Symbol(foo, Decl(optionalChainingInTypeAssertions.ts, 4, 5))
26+
>m : Symbol(Foo.m, Decl(optionalChainingInTypeAssertions.ts, 0, 11))
27+
28+
/*b1*/(/*b2*/<any>foo.m/*b3*/)/*b4*/?.();
29+
>foo.m : Symbol(Foo.m, Decl(optionalChainingInTypeAssertions.ts, 0, 11))
30+
>foo : Symbol(foo, Decl(optionalChainingInTypeAssertions.ts, 4, 5))
31+
>m : Symbol(Foo.m, Decl(optionalChainingInTypeAssertions.ts, 0, 11))
32+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
=== tests/cases/conformance/expressions/optionalChaining/optionalChainingInTypeAssertions.ts ===
2+
class Foo {
3+
>Foo : Foo
4+
5+
m() {}
6+
>m : () => void
7+
}
8+
9+
const foo = new Foo();
10+
>foo : Foo
11+
>new Foo() : Foo
12+
>Foo : typeof Foo
13+
14+
(foo.m as any)?.();
15+
>(foo.m as any)?.() : any
16+
>(foo.m as any) : any
17+
>foo.m as any : any
18+
>foo.m : () => void
19+
>foo : Foo
20+
>m : () => void
21+
22+
(<any>foo.m)?.();
23+
>(<any>foo.m)?.() : any
24+
>(<any>foo.m) : any
25+
><any>foo.m : any
26+
>foo.m : () => void
27+
>foo : Foo
28+
>m : () => void
29+
30+
/*a1*/(/*a2*/foo.m as any/*a3*/)/*a4*/?.();
31+
>(/*a2*/foo.m as any/*a3*/)/*a4*/?.() : any
32+
>(/*a2*/foo.m as any/*a3*/) : any
33+
>foo.m as any : any
34+
>foo.m : () => void
35+
>foo : Foo
36+
>m : () => void
37+
38+
/*b1*/(/*b2*/<any>foo.m/*b3*/)/*b4*/?.();
39+
>(/*b2*/<any>foo.m/*b3*/)/*b4*/?.() : any
40+
>(/*b2*/<any>foo.m/*b3*/) : any
41+
><any>foo.m : any
42+
>foo.m : () => void
43+
>foo : Foo
44+
>m : () => void
45+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// @target: es2015, esnext
2+
3+
class Foo {
4+
m() {}
5+
}
6+
7+
const foo = new Foo();
8+
9+
(foo.m as any)?.();
10+
(<any>foo.m)?.();
11+
12+
/*a1*/(/*a2*/foo.m as any/*a3*/)/*a4*/?.();
13+
/*b1*/(/*b2*/<any>foo.m/*b3*/)/*b4*/?.();

0 commit comments

Comments
 (0)