Skip to content

Commit 72dfc58

Browse files
authored
Retain CheckFlags.Late on symbols manufactured based on Late-bound symbols (microsoft#42205)
1 parent b405fdd commit 72dfc58

6 files changed

+184
-3
lines changed

src/compiler/checker.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10630,6 +10630,10 @@ namespace ts {
1063010630
return type;
1063110631
}
1063210632

10633+
function getIsLateCheckFlag(s: Symbol): CheckFlags {
10634+
return getCheckFlags(s) & CheckFlags.Late;
10635+
}
10636+
1063310637
/** Resolve the members of a mapped type { [P in K]: T } */
1063410638
function resolveMappedTypeMembers(type: MappedType) {
1063510639
const members: SymbolTable = createSymbolTable();
@@ -10688,8 +10692,9 @@ namespace ts {
1068810692
const isReadonly = !!(templateModifiers & MappedTypeModifiers.IncludeReadonly ||
1068910693
!(templateModifiers & MappedTypeModifiers.ExcludeReadonly) && modifiersProp && isReadonlySymbol(modifiersProp));
1069010694
const stripOptional = strictNullChecks && !isOptional && modifiersProp && modifiersProp.flags & SymbolFlags.Optional;
10695+
const lateFlag: CheckFlags = modifiersProp ? getIsLateCheckFlag(modifiersProp) : 0;
1069110696
const prop = <MappedSymbol>createSymbol(SymbolFlags.Property | (isOptional ? SymbolFlags.Optional : 0), propName,
10692-
CheckFlags.Mapped | (isReadonly ? CheckFlags.Readonly : 0) | (stripOptional ? CheckFlags.StripOptional : 0));
10697+
lateFlag | CheckFlags.Mapped | (isReadonly ? CheckFlags.Readonly : 0) | (stripOptional ? CheckFlags.StripOptional : 0));
1069310698
prop.mappedType = type;
1069410699
prop.nameType = propNameType;
1069510700
prop.keyType = keyType;
@@ -14666,7 +14671,7 @@ namespace ts {
1466614671
else if (isSpreadableProperty(prop)) {
1466714672
const isSetonlyAccessor = prop.flags & SymbolFlags.SetAccessor && !(prop.flags & SymbolFlags.GetAccessor);
1466814673
const flags = SymbolFlags.Property | SymbolFlags.Optional;
14669-
const result = createSymbol(flags, prop.escapedName, readonly ? CheckFlags.Readonly : 0);
14674+
const result = createSymbol(flags, prop.escapedName, getIsLateCheckFlag(prop) | (readonly ? CheckFlags.Readonly : 0));
1467014675
result.type = isSetonlyAccessor ? undefinedType : getTypeOfSymbol(prop);
1467114676
result.declarations = prop.declarations;
1467214677
result.nameType = getSymbolLinks(prop).nameType;
@@ -14814,7 +14819,7 @@ namespace ts {
1481414819
return prop;
1481514820
}
1481614821
const flags = SymbolFlags.Property | (prop.flags & SymbolFlags.Optional);
14817-
const result = createSymbol(flags, prop.escapedName, readonly ? CheckFlags.Readonly : 0);
14822+
const result = createSymbol(flags, prop.escapedName, getIsLateCheckFlag(prop) | (readonly ? CheckFlags.Readonly : 0));
1481814823
result.type = isSetonlyAccessor ? undefinedType : getTypeOfSymbol(prop);
1481914824
result.declarations = prop.declarations;
1482014825
result.nameType = getSymbolLinks(prop).nameType;
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
tests/cases/compiler/index.ts(3,14): error TS4023: Exported variable 'spread' has or is using name 'SYMBOL' from external module "tests/cases/compiler/bug" but cannot be named.
2+
3+
4+
==== tests/cases/compiler/bug.ts (0 errors) ====
5+
export const SYMBOL = Symbol()
6+
7+
export interface Interface {
8+
readonly [SYMBOL]: string; // remove readonly and @showEmit to see the expected error
9+
}
10+
11+
export function createInstance(): Interface {
12+
return {
13+
[SYMBOL]: ''
14+
}
15+
}
16+
17+
==== tests/cases/compiler/index.ts (1 errors) ====
18+
import { createInstance } from './bug'
19+
20+
export const spread = {
21+
~~~~~~
22+
!!! error TS4023: Exported variable 'spread' has or is using name 'SYMBOL' from external module "tests/cases/compiler/bug" but cannot be named.
23+
...createInstance(),
24+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
//// [tests/cases/compiler/declarationEmitReadonlyComputedProperty.ts] ////
2+
3+
//// [bug.ts]
4+
export const SYMBOL = Symbol()
5+
6+
export interface Interface {
7+
readonly [SYMBOL]: string; // remove readonly and @showEmit to see the expected error
8+
}
9+
10+
export function createInstance(): Interface {
11+
return {
12+
[SYMBOL]: ''
13+
}
14+
}
15+
16+
//// [index.ts]
17+
import { createInstance } from './bug'
18+
19+
export const spread = {
20+
...createInstance(),
21+
}
22+
23+
//// [bug.js]
24+
"use strict";
25+
exports.__esModule = true;
26+
exports.createInstance = exports.SYMBOL = void 0;
27+
exports.SYMBOL = Symbol();
28+
function createInstance() {
29+
var _a;
30+
return _a = {},
31+
_a[exports.SYMBOL] = '',
32+
_a;
33+
}
34+
exports.createInstance = createInstance;
35+
//// [index.js]
36+
"use strict";
37+
var __assign = (this && this.__assign) || function () {
38+
__assign = Object.assign || function(t) {
39+
for (var s, i = 1, n = arguments.length; i < n; i++) {
40+
s = arguments[i];
41+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
42+
t[p] = s[p];
43+
}
44+
return t;
45+
};
46+
return __assign.apply(this, arguments);
47+
};
48+
exports.__esModule = true;
49+
exports.spread = void 0;
50+
var bug_1 = require("./bug");
51+
exports.spread = __assign({}, bug_1.createInstance());
52+
53+
54+
//// [bug.d.ts]
55+
export declare const SYMBOL: unique symbol;
56+
export interface Interface {
57+
readonly [SYMBOL]: string;
58+
}
59+
export declare function createInstance(): Interface;
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
=== tests/cases/compiler/bug.ts ===
2+
export const SYMBOL = Symbol()
3+
>SYMBOL : Symbol(SYMBOL, Decl(bug.ts, 0, 12))
4+
>Symbol : Symbol(Symbol, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --))
5+
6+
export interface Interface {
7+
>Interface : Symbol(Interface, Decl(bug.ts, 0, 30))
8+
9+
readonly [SYMBOL]: string; // remove readonly and @showEmit to see the expected error
10+
>[SYMBOL] : Symbol(Interface[SYMBOL], Decl(bug.ts, 2, 28))
11+
>SYMBOL : Symbol(SYMBOL, Decl(bug.ts, 0, 12))
12+
}
13+
14+
export function createInstance(): Interface {
15+
>createInstance : Symbol(createInstance, Decl(bug.ts, 4, 1))
16+
>Interface : Symbol(Interface, Decl(bug.ts, 0, 30))
17+
18+
return {
19+
[SYMBOL]: ''
20+
>[SYMBOL] : Symbol([SYMBOL], Decl(bug.ts, 7, 10))
21+
>SYMBOL : Symbol(SYMBOL, Decl(bug.ts, 0, 12))
22+
}
23+
}
24+
25+
=== tests/cases/compiler/index.ts ===
26+
import { createInstance } from './bug'
27+
>createInstance : Symbol(createInstance, Decl(index.ts, 0, 8))
28+
29+
export const spread = {
30+
>spread : Symbol(spread, Decl(index.ts, 2, 12))
31+
32+
...createInstance(),
33+
>createInstance : Symbol(createInstance, Decl(index.ts, 0, 8))
34+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
=== tests/cases/compiler/bug.ts ===
2+
export const SYMBOL = Symbol()
3+
>SYMBOL : unique symbol
4+
>Symbol() : unique symbol
5+
>Symbol : SymbolConstructor
6+
7+
export interface Interface {
8+
readonly [SYMBOL]: string; // remove readonly and @showEmit to see the expected error
9+
>[SYMBOL] : string
10+
>SYMBOL : unique symbol
11+
}
12+
13+
export function createInstance(): Interface {
14+
>createInstance : () => Interface
15+
16+
return {
17+
>{ [SYMBOL]: '' } : { [SYMBOL]: string; }
18+
19+
[SYMBOL]: ''
20+
>[SYMBOL] : string
21+
>SYMBOL : unique symbol
22+
>'' : ""
23+
}
24+
}
25+
26+
=== tests/cases/compiler/index.ts ===
27+
import { createInstance } from './bug'
28+
>createInstance : () => import("tests/cases/compiler/bug").Interface
29+
30+
export const spread = {
31+
>spread : { [SYMBOL]: string; }
32+
>{ ...createInstance(),} : { [SYMBOL]: string; }
33+
34+
...createInstance(),
35+
>createInstance() : import("tests/cases/compiler/bug").Interface
36+
>createInstance : () => import("tests/cases/compiler/bug").Interface
37+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// @declaration: true
2+
// @lib: es2015
3+
4+
// @filename: bug.ts
5+
export const SYMBOL = Symbol()
6+
7+
export interface Interface {
8+
readonly [SYMBOL]: string; // remove readonly and @showEmit to see the expected error
9+
}
10+
11+
export function createInstance(): Interface {
12+
return {
13+
[SYMBOL]: ''
14+
}
15+
}
16+
17+
// @filename: index.ts
18+
import { createInstance } from './bug'
19+
20+
export const spread = {
21+
...createInstance(),
22+
}

0 commit comments

Comments
 (0)