Skip to content

Commit

Permalink
Retain CheckFlags.Late on symbols manufactured based on Late-bound sy…
Browse files Browse the repository at this point in the history
…mbols (#42205)
  • Loading branch information
weswigham authored Jan 4, 2021
1 parent b405fdd commit 72dfc58
Show file tree
Hide file tree
Showing 6 changed files with 184 additions and 3 deletions.
11 changes: 8 additions & 3 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
@@ -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(),
}
Original file line number Diff line number Diff line change
@@ -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;
Original file line number Diff line number Diff line change
@@ -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))
}
Original file line number Diff line number Diff line change
@@ -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
}
22 changes: 22 additions & 0 deletions tests/cases/compiler/declarationEmitReadonlyComputedProperty.ts
Original file line number Diff line number Diff line change
@@ -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(),
}

0 comments on commit 72dfc58

Please sign in to comment.