Retain CheckFlags.Late on symbols manufactured based on Late-bound symbols (#42205)

This commit is contained in:
Wesley Wigham
2021-01-04 15:49:52 -08:00
committed by GitHub
parent b405fdd2ab
commit 72dfc589a1
6 changed files with 184 additions and 3 deletions

View File

@@ -10630,6 +10630,10 @@ namespace ts {
return type;
}
function getIsLateCheckFlag(s: Symbol): CheckFlags {
return getCheckFlags(s) & CheckFlags.Late;
}
/** Resolve the members of a mapped type { [P in K]: T } */
function resolveMappedTypeMembers(type: MappedType) {
const members: SymbolTable = createSymbolTable();
@@ -10688,8 +10692,9 @@ namespace ts {
const isReadonly = !!(templateModifiers & MappedTypeModifiers.IncludeReadonly ||
!(templateModifiers & MappedTypeModifiers.ExcludeReadonly) && modifiersProp && isReadonlySymbol(modifiersProp));
const stripOptional = strictNullChecks && !isOptional && modifiersProp && modifiersProp.flags & SymbolFlags.Optional;
const lateFlag: CheckFlags = modifiersProp ? getIsLateCheckFlag(modifiersProp) : 0;
const prop = <MappedSymbol>createSymbol(SymbolFlags.Property | (isOptional ? SymbolFlags.Optional : 0), propName,
CheckFlags.Mapped | (isReadonly ? CheckFlags.Readonly : 0) | (stripOptional ? CheckFlags.StripOptional : 0));
lateFlag | CheckFlags.Mapped | (isReadonly ? CheckFlags.Readonly : 0) | (stripOptional ? CheckFlags.StripOptional : 0));
prop.mappedType = type;
prop.nameType = propNameType;
prop.keyType = keyType;
@@ -14666,7 +14671,7 @@ namespace ts {
else if (isSpreadableProperty(prop)) {
const isSetonlyAccessor = prop.flags & SymbolFlags.SetAccessor && !(prop.flags & SymbolFlags.GetAccessor);
const flags = SymbolFlags.Property | SymbolFlags.Optional;
const result = createSymbol(flags, prop.escapedName, readonly ? CheckFlags.Readonly : 0);
const result = createSymbol(flags, prop.escapedName, getIsLateCheckFlag(prop) | (readonly ? CheckFlags.Readonly : 0));
result.type = isSetonlyAccessor ? undefinedType : getTypeOfSymbol(prop);
result.declarations = prop.declarations;
result.nameType = getSymbolLinks(prop).nameType;
@@ -14814,7 +14819,7 @@ namespace ts {
return prop;
}
const flags = SymbolFlags.Property | (prop.flags & SymbolFlags.Optional);
const result = createSymbol(flags, prop.escapedName, readonly ? CheckFlags.Readonly : 0);
const result = createSymbol(flags, prop.escapedName, getIsLateCheckFlag(prop) | (readonly ? CheckFlags.Readonly : 0));
result.type = isSetonlyAccessor ? undefinedType : getTypeOfSymbol(prop);
result.declarations = prop.declarations;
result.nameType = getSymbolLinks(prop).nameType;

View File

@@ -0,0 +1,24 @@
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.
==== tests/cases/compiler/bug.ts (0 errors) ====
export const SYMBOL = Symbol()
export interface Interface {
readonly [SYMBOL]: string; // remove readonly and @showEmit to see the expected error
}
export function createInstance(): Interface {
return {
[SYMBOL]: ''
}
}
==== tests/cases/compiler/index.ts (1 errors) ====
import { createInstance } from './bug'
export const spread = {
~~~~~~
!!! error TS4023: Exported variable 'spread' has or is using name 'SYMBOL' from external module "tests/cases/compiler/bug" but cannot be named.
...createInstance(),
}

View File

@@ -0,0 +1,59 @@
//// [tests/cases/compiler/declarationEmitReadonlyComputedProperty.ts] ////
//// [bug.ts]
export const SYMBOL = Symbol()
export interface Interface {
readonly [SYMBOL]: string; // remove readonly and @showEmit to see the expected error
}
export function createInstance(): Interface {
return {
[SYMBOL]: ''
}
}
//// [index.ts]
import { createInstance } from './bug'
export const spread = {
...createInstance(),
}
//// [bug.js]
"use strict";
exports.__esModule = true;
exports.createInstance = exports.SYMBOL = void 0;
exports.SYMBOL = Symbol();
function createInstance() {
var _a;
return _a = {},
_a[exports.SYMBOL] = '',
_a;
}
exports.createInstance = createInstance;
//// [index.js]
"use strict";
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
exports.__esModule = true;
exports.spread = void 0;
var bug_1 = require("./bug");
exports.spread = __assign({}, bug_1.createInstance());
//// [bug.d.ts]
export declare const SYMBOL: unique symbol;
export interface Interface {
readonly [SYMBOL]: string;
}
export declare function createInstance(): Interface;

View File

@@ -0,0 +1,34 @@
=== tests/cases/compiler/bug.ts ===
export const SYMBOL = Symbol()
>SYMBOL : Symbol(SYMBOL, Decl(bug.ts, 0, 12))
>Symbol : Symbol(Symbol, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --))
export interface Interface {
>Interface : Symbol(Interface, Decl(bug.ts, 0, 30))
readonly [SYMBOL]: string; // remove readonly and @showEmit to see the expected error
>[SYMBOL] : Symbol(Interface[SYMBOL], Decl(bug.ts, 2, 28))
>SYMBOL : Symbol(SYMBOL, Decl(bug.ts, 0, 12))
}
export function createInstance(): Interface {
>createInstance : Symbol(createInstance, Decl(bug.ts, 4, 1))
>Interface : Symbol(Interface, Decl(bug.ts, 0, 30))
return {
[SYMBOL]: ''
>[SYMBOL] : Symbol([SYMBOL], Decl(bug.ts, 7, 10))
>SYMBOL : Symbol(SYMBOL, Decl(bug.ts, 0, 12))
}
}
=== tests/cases/compiler/index.ts ===
import { createInstance } from './bug'
>createInstance : Symbol(createInstance, Decl(index.ts, 0, 8))
export const spread = {
>spread : Symbol(spread, Decl(index.ts, 2, 12))
...createInstance(),
>createInstance : Symbol(createInstance, Decl(index.ts, 0, 8))
}

View File

@@ -0,0 +1,37 @@
=== tests/cases/compiler/bug.ts ===
export const SYMBOL = Symbol()
>SYMBOL : unique symbol
>Symbol() : unique symbol
>Symbol : SymbolConstructor
export interface Interface {
readonly [SYMBOL]: string; // remove readonly and @showEmit to see the expected error
>[SYMBOL] : string
>SYMBOL : unique symbol
}
export function createInstance(): Interface {
>createInstance : () => Interface
return {
>{ [SYMBOL]: '' } : { [SYMBOL]: string; }
[SYMBOL]: ''
>[SYMBOL] : string
>SYMBOL : unique symbol
>'' : ""
}
}
=== tests/cases/compiler/index.ts ===
import { createInstance } from './bug'
>createInstance : () => import("tests/cases/compiler/bug").Interface
export const spread = {
>spread : { [SYMBOL]: string; }
>{ ...createInstance(),} : { [SYMBOL]: string; }
...createInstance(),
>createInstance() : import("tests/cases/compiler/bug").Interface
>createInstance : () => import("tests/cases/compiler/bug").Interface
}

View File

@@ -0,0 +1,22 @@
// @declaration: true
// @lib: es2015
// @filename: bug.ts
export const SYMBOL = Symbol()
export interface Interface {
readonly [SYMBOL]: string; // remove readonly and @showEmit to see the expected error
}
export function createInstance(): Interface {
return {
[SYMBOL]: ''
}
}
// @filename: index.ts
import { createInstance } from './bug'
export const spread = {
...createInstance(),
}