Support declaration emit for late bound element accesses assigned to functions in both TS and JS (#36593)

This commit is contained in:
Wesley Wigham 2020-02-25 13:45:27 -08:00 committed by GitHub
parent 7d8dc730b7
commit 3e4ce4777d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 449 additions and 13 deletions

View File

@ -3069,9 +3069,20 @@ namespace ts {
function resolveExternalModuleSymbol(moduleSymbol: Symbol | undefined, dontResolveAlias?: boolean): Symbol | undefined;
function resolveExternalModuleSymbol(moduleSymbol: Symbol, dontResolveAlias?: boolean): Symbol {
if (moduleSymbol) {
const links = getSymbolLinks(moduleSymbol);
if (!dontResolveAlias) {
links.resolvedExternalModuleSymbol = "circular";
}
const exportEquals = resolveSymbol(moduleSymbol.exports!.get(InternalSymbolName.ExportEquals), dontResolveAlias);
const exported = getCommonJsExportEquals(getMergedSymbol(exportEquals), getMergedSymbol(moduleSymbol));
return getMergedSymbol(exported) || moduleSymbol;
const result = getMergedSymbol(exported) || moduleSymbol;
if (!dontResolveAlias) {
// we "cache" this result, but because both the input _and_ the output are mergeable, literally every call could need
// a different result, assuming the inputs and outputs get merged with. So instead we just use this as a flag that
// export assignment resolution has occured on this symbol at least once. (because it might happen many times!)
links.resolvedExternalModuleSymbol = result;
}
return result;
}
return undefined!;
}
@ -5543,7 +5554,7 @@ namespace ts {
function serializeSymbolWorker(symbol: Symbol, isPrivate: boolean, propertyAsAlias: boolean) {
const symbolName = unescapeLeadingUnderscores(symbol.escapedName);
const isDefault = symbol.escapedName === InternalSymbolName.Default;
if (isStringANonContextualKeyword(symbolName) && !isDefault) {
if ((isStringANonContextualKeyword(symbolName) || !isIdentifierText(symbolName, languageVersion)) && !isDefault && symbol.escapedName !== InternalSymbolName.ExportEquals) {
// Oh no. We cannot use this symbol's name as it's name... It's likely some jsdoc had an invalid name like `export` or `default` :(
context.encounteredError = true;
// TODO: Issue error via symbol tracker?
@ -5694,7 +5705,8 @@ namespace ts {
}
function getNamespaceMembersForSerialization(symbol: Symbol) {
return !symbol.exports ? [] : filter(arrayFrom((symbol.exports).values()), p => !((p.flags & SymbolFlags.Prototype) || (p.escapedName === "prototype")));
const exports = getExportsOfSymbol(symbol);
return !exports ? [] : filter(arrayFrom((exports).values()), p => !((p.flags & SymbolFlags.Prototype) || (p.escapedName === "prototype")));
}
function isTypeOnlyNamespace(symbol: Symbol) {
@ -8896,6 +8908,17 @@ namespace ts {
function getResolvedMembersOrExportsOfSymbol(symbol: Symbol, resolutionKind: MembersOrExportsResolutionKind): UnderscoreEscapedMap<Symbol> {
const links = getSymbolLinks(symbol);
if (!links[resolutionKind]) {
// We _must_ resolve any possible commonjs export assignments _before_ merging in late bound members, as cjs export assignments may cause
// things to be merged (?!?) into this symbol; moreover, we _can't_ resolve those export assignments if we're already resolving the containing
// module (as then we'll issue a circularity error)
const p = symbol.valueDeclaration?.parent;
if (p && isSourceFile(p) && p.symbol && !getSymbolLinks(p.symbol).resolvedExternalModuleSymbol) {
const exported = resolveExternalModuleSymbol(p.symbol);
const targetLinks = exported && getSymbolLinks(exported);
if (targetLinks && targetLinks[resolutionKind]) {
return links[resolutionKind] = targetLinks[resolutionKind]!;
}
}
const isStatic = resolutionKind === MembersOrExportsResolutionKind.resolvedExports;
const earlySymbols = !isStatic ? symbol.members :
symbol.flags & SymbolFlags.Module ? getExportsOfModuleWorker(symbol) :
@ -35274,8 +35297,8 @@ namespace ts {
}
}
function createTypeOfDeclaration(declarationIn: AccessorDeclaration | VariableLikeDeclaration | PropertyAccessExpression, enclosingDeclaration: Node, flags: NodeBuilderFlags, tracker: SymbolTracker, addUndefined?: boolean) {
const declaration = getParseTreeNode(declarationIn, isVariableLikeOrAccessor);
function createTypeOfDeclaration(declarationIn: AccessorDeclaration | VariableLikeDeclaration | PropertyAccessExpression | ElementAccessExpression | BinaryExpression, enclosingDeclaration: Node, flags: NodeBuilderFlags, tracker: SymbolTracker, addUndefined?: boolean) {
const declaration = getParseTreeNode(declarationIn, isPossiblyPropertyLikeDeclaration);
if (!declaration) {
return createToken(SyntaxKind.AnyKeyword) as KeywordTypeNode;
}

View File

@ -1157,13 +1157,20 @@ namespace ts {
fakespace.locals = createSymbolTable(props);
fakespace.symbol = props[0].parent!;
const declarations = mapDefined(props, p => {
if (!isPropertyAccessExpression(p.valueDeclaration)) {
return undefined; // TODO GH#33569: Handle element access expressions that created late bound names (rather than silently omitting them)
if (!isPropertyAccessExpression(p.valueDeclaration) && !isElementAccessExpression(p.valueDeclaration) && !isBinaryExpression(p.valueDeclaration)) {
return undefined;
}
if (hasDynamicName(p.valueDeclaration) && !resolver.isLateBound(getParseTreeNode(p.valueDeclaration) as Declaration)) {
return undefined;
}
const name = unescapeLeadingUnderscores(p.escapedName);
if (!isIdentifierText(name, ScriptTarget.ES3)) {
return undefined; // TODO: Rather than quietly eliding (as is current behavior), maybe we should issue errors?
}
getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(p.valueDeclaration);
const type = resolver.createTypeOfDeclaration(p.valueDeclaration, fakespace, declarationEmitNodeBuilderFlags, symbolTracker);
getSymbolAccessibilityDiagnostic = oldDiag;
const varDecl = createVariableDeclaration(unescapeLeadingUnderscores(p.escapedName), type, /*initializer*/ undefined);
const varDecl = createVariableDeclaration(name, type, /*initializer*/ undefined);
return createVariableStatement(/*modifiers*/ undefined, createVariableDeclarationList([varDecl]));
});
const namespaceDecl = createModuleDeclaration(/*decorators*/ undefined, ensureModifiers(input), input.name!, createModuleBlock(declarations), NodeFlags.Namespace);

View File

@ -27,7 +27,9 @@ namespace ts {
| TypeAliasDeclaration
| ConstructorDeclaration
| IndexSignatureDeclaration
| PropertyAccessExpression;
| PropertyAccessExpression
| ElementAccessExpression
| BinaryExpression;
export function canProduceDiagnostics(node: Node): node is DeclarationDiagnosticProducing {
return isVariableDeclaration(node) ||
@ -48,7 +50,9 @@ namespace ts {
isTypeAliasDeclaration(node) ||
isConstructorDeclaration(node) ||
isIndexSignatureDeclaration(node) ||
isPropertyAccessExpression(node);
isPropertyAccessExpression(node) ||
isElementAccessExpression(node) ||
isBinaryExpression(node);
}
export function createGetSymbolAccessibilityDiagnosticForNodeName(node: DeclarationDiagnosticProducing) {
@ -125,7 +129,7 @@ namespace ts {
}
export function createGetSymbolAccessibilityDiagnosticForNode(node: DeclarationDiagnosticProducing): (symbolAccessibilityResult: SymbolAccessibilityResult) => SymbolAccessibilityDiagnostic | undefined {
if (isVariableDeclaration(node) || isPropertyDeclaration(node) || isPropertySignature(node) || isPropertyAccessExpression(node) || isBindingElement(node) || isConstructorDeclaration(node)) {
if (isVariableDeclaration(node) || isPropertyDeclaration(node) || isPropertySignature(node) || isPropertyAccessExpression(node) || isElementAccessExpression(node) || isBinaryExpression(node) || isBindingElement(node) || isConstructorDeclaration(node)) {
return getVariableDeclarationTypeVisibilityError;
}
else if (isSetAccessor(node) || isGetAccessor(node)) {
@ -166,7 +170,7 @@ namespace ts {
}
// This check is to ensure we don't report error on constructor parameter property as that error would be reported during parameter emit
// The only exception here is if the constructor was marked as private. we are not emitting the constructor parameters at all.
else if (node.kind === SyntaxKind.PropertyDeclaration || node.kind === SyntaxKind.PropertyAccessExpression || node.kind === SyntaxKind.PropertySignature ||
else if (node.kind === SyntaxKind.PropertyDeclaration || node.kind === SyntaxKind.PropertyAccessExpression || node.kind === SyntaxKind.ElementAccessExpression || node.kind === SyntaxKind.BinaryExpression || node.kind === SyntaxKind.PropertySignature ||
(node.kind === SyntaxKind.Parameter && hasModifier(node.parent, ModifierFlags.Private))) {
// TODO(jfreeman): Deal with computed properties in error reporting.
if (hasModifier(node, ModifierFlags.Static)) {

View File

@ -3930,7 +3930,7 @@ namespace ts {
isOptionalUninitializedParameterProperty(node: ParameterDeclaration): boolean;
isExpandoFunctionDeclaration(node: FunctionDeclaration): boolean;
getPropertiesOfContainerFunction(node: Declaration): Symbol[];
createTypeOfDeclaration(declaration: AccessorDeclaration | VariableLikeDeclaration | PropertyAccessExpression, enclosingDeclaration: Node, flags: NodeBuilderFlags, tracker: SymbolTracker, addUndefined?: boolean): TypeNode | undefined;
createTypeOfDeclaration(declaration: AccessorDeclaration | VariableLikeDeclaration | PropertyAccessExpression | ElementAccessExpression | BinaryExpression, enclosingDeclaration: Node, flags: NodeBuilderFlags, tracker: SymbolTracker, addUndefined?: boolean): TypeNode | undefined;
createReturnTypeOfSignatureDeclaration(signatureDeclaration: SignatureDeclaration, enclosingDeclaration: Node, flags: NodeBuilderFlags, tracker: SymbolTracker): TypeNode | undefined;
createTypeOfExpression(expr: Expression, enclosingDeclaration: Node, flags: NodeBuilderFlags, tracker: SymbolTracker): TypeNode | undefined;
createLiteralConstValue(node: VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration, tracker: SymbolTracker): Expression;
@ -4104,6 +4104,7 @@ namespace ts {
deferralParent?: Type; // Source union/intersection of a deferred type
cjsExportMerged?: Symbol; // Version of the symbol with all non export= exports merged with the export= target
typeOnlyDeclaration?: TypeOnlyCompatibleAliasDeclaration | false; // First resolved alias declaration that makes the symbol only usable in type constructs
resolvedExternalModuleSymbol?: Symbol | "circular"; // Cached result of `resolveExternalModuleSymbol`
}
/* @internal */

View File

@ -1299,6 +1299,10 @@ namespace ts {
return isVariableLike(node) || isAccessor(node);
}
export function isPossiblyPropertyLikeDeclaration(node: Node): node is AccessorDeclaration | VariableLikeDeclaration | PropertyAccessExpression | ElementAccessExpression {
return isVariableLikeOrAccessor(node) || isPropertyAccessExpression(node) || isElementAccessExpression(node) || isBinaryExpression(node);
}
export function isVariableDeclarationInVariableStatement(node: VariableDeclaration) {
return node.parent.kind === SyntaxKind.VariableDeclarationList
&& node.parent.parent.kind === SyntaxKind.VariableStatement;

View File

@ -0,0 +1,40 @@
//// [lateBoundElementAccessAssignmentDeclarations.ts]
export function foo() {}
foo.bar = 12;
const _private = Symbol();
foo[_private] = "ok";
const strMem = "strMemName";
foo[strMem] = "ok";
const dashStrMem = "dashed-str-mem";
foo[dashStrMem] = "ok";
const numMem = 42;
foo[numMem] = "ok";
const x: string = foo[_private];
const y: string = foo[strMem];
const z: string = foo[numMem];
const a: string = foo[dashStrMem];
//// [lateBoundElementAccessAssignmentDeclarations.js]
export function foo() { }
foo.bar = 12;
const _private = Symbol();
foo[_private] = "ok";
const strMem = "strMemName";
foo[strMem] = "ok";
const dashStrMem = "dashed-str-mem";
foo[dashStrMem] = "ok";
const numMem = 42;
foo[numMem] = "ok";
const x = foo[_private];
const y = foo[strMem];
const z = foo[numMem];
const a = foo[dashStrMem];
//// [lateBoundElementAccessAssignmentDeclarations.d.ts]
export declare function foo(): void;
export declare namespace foo {
var bar: number;
var strMemName: string;
}

View File

@ -0,0 +1,58 @@
=== tests/cases/compiler/lateBoundElementAccessAssignmentDeclarations.ts ===
export function foo() {}
>foo : Symbol(foo, Decl(lateBoundElementAccessAssignmentDeclarations.ts, 0, 0), Decl(lateBoundElementAccessAssignmentDeclarations.ts, 0, 24), Decl(lateBoundElementAccessAssignmentDeclarations.ts, 2, 26), Decl(lateBoundElementAccessAssignmentDeclarations.ts, 4, 28), Decl(lateBoundElementAccessAssignmentDeclarations.ts, 6, 36) ... and 1 more)
foo.bar = 12;
>foo.bar : Symbol(foo.bar, Decl(lateBoundElementAccessAssignmentDeclarations.ts, 0, 24))
>foo : Symbol(foo, Decl(lateBoundElementAccessAssignmentDeclarations.ts, 0, 0), Decl(lateBoundElementAccessAssignmentDeclarations.ts, 0, 24), Decl(lateBoundElementAccessAssignmentDeclarations.ts, 2, 26), Decl(lateBoundElementAccessAssignmentDeclarations.ts, 4, 28), Decl(lateBoundElementAccessAssignmentDeclarations.ts, 6, 36) ... and 1 more)
>bar : Symbol(foo.bar, Decl(lateBoundElementAccessAssignmentDeclarations.ts, 0, 24))
const _private = Symbol();
>_private : Symbol(_private, Decl(lateBoundElementAccessAssignmentDeclarations.ts, 2, 5))
>Symbol : Symbol(Symbol, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --))
foo[_private] = "ok";
>foo : Symbol(foo, Decl(lateBoundElementAccessAssignmentDeclarations.ts, 0, 0), Decl(lateBoundElementAccessAssignmentDeclarations.ts, 0, 24), Decl(lateBoundElementAccessAssignmentDeclarations.ts, 2, 26), Decl(lateBoundElementAccessAssignmentDeclarations.ts, 4, 28), Decl(lateBoundElementAccessAssignmentDeclarations.ts, 6, 36) ... and 1 more)
>_private : Symbol(_private, Decl(lateBoundElementAccessAssignmentDeclarations.ts, 2, 5))
const strMem = "strMemName";
>strMem : Symbol(strMem, Decl(lateBoundElementAccessAssignmentDeclarations.ts, 4, 5))
foo[strMem] = "ok";
>foo : Symbol(foo, Decl(lateBoundElementAccessAssignmentDeclarations.ts, 0, 0), Decl(lateBoundElementAccessAssignmentDeclarations.ts, 0, 24), Decl(lateBoundElementAccessAssignmentDeclarations.ts, 2, 26), Decl(lateBoundElementAccessAssignmentDeclarations.ts, 4, 28), Decl(lateBoundElementAccessAssignmentDeclarations.ts, 6, 36) ... and 1 more)
>strMem : Symbol(strMem, Decl(lateBoundElementAccessAssignmentDeclarations.ts, 4, 5))
const dashStrMem = "dashed-str-mem";
>dashStrMem : Symbol(dashStrMem, Decl(lateBoundElementAccessAssignmentDeclarations.ts, 6, 5))
foo[dashStrMem] = "ok";
>foo : Symbol(foo, Decl(lateBoundElementAccessAssignmentDeclarations.ts, 0, 0), Decl(lateBoundElementAccessAssignmentDeclarations.ts, 0, 24), Decl(lateBoundElementAccessAssignmentDeclarations.ts, 2, 26), Decl(lateBoundElementAccessAssignmentDeclarations.ts, 4, 28), Decl(lateBoundElementAccessAssignmentDeclarations.ts, 6, 36) ... and 1 more)
>dashStrMem : Symbol(dashStrMem, Decl(lateBoundElementAccessAssignmentDeclarations.ts, 6, 5))
const numMem = 42;
>numMem : Symbol(numMem, Decl(lateBoundElementAccessAssignmentDeclarations.ts, 8, 5))
foo[numMem] = "ok";
>foo : Symbol(foo, Decl(lateBoundElementAccessAssignmentDeclarations.ts, 0, 0), Decl(lateBoundElementAccessAssignmentDeclarations.ts, 0, 24), Decl(lateBoundElementAccessAssignmentDeclarations.ts, 2, 26), Decl(lateBoundElementAccessAssignmentDeclarations.ts, 4, 28), Decl(lateBoundElementAccessAssignmentDeclarations.ts, 6, 36) ... and 1 more)
>numMem : Symbol(numMem, Decl(lateBoundElementAccessAssignmentDeclarations.ts, 8, 5))
const x: string = foo[_private];
>x : Symbol(x, Decl(lateBoundElementAccessAssignmentDeclarations.ts, 11, 5))
>foo : Symbol(foo, Decl(lateBoundElementAccessAssignmentDeclarations.ts, 0, 0), Decl(lateBoundElementAccessAssignmentDeclarations.ts, 0, 24), Decl(lateBoundElementAccessAssignmentDeclarations.ts, 2, 26), Decl(lateBoundElementAccessAssignmentDeclarations.ts, 4, 28), Decl(lateBoundElementAccessAssignmentDeclarations.ts, 6, 36) ... and 1 more)
>_private : Symbol(_private, Decl(lateBoundElementAccessAssignmentDeclarations.ts, 2, 5))
const y: string = foo[strMem];
>y : Symbol(y, Decl(lateBoundElementAccessAssignmentDeclarations.ts, 12, 5))
>foo : Symbol(foo, Decl(lateBoundElementAccessAssignmentDeclarations.ts, 0, 0), Decl(lateBoundElementAccessAssignmentDeclarations.ts, 0, 24), Decl(lateBoundElementAccessAssignmentDeclarations.ts, 2, 26), Decl(lateBoundElementAccessAssignmentDeclarations.ts, 4, 28), Decl(lateBoundElementAccessAssignmentDeclarations.ts, 6, 36) ... and 1 more)
>strMem : Symbol(strMem, Decl(lateBoundElementAccessAssignmentDeclarations.ts, 4, 5))
const z: string = foo[numMem];
>z : Symbol(z, Decl(lateBoundElementAccessAssignmentDeclarations.ts, 13, 5))
>foo : Symbol(foo, Decl(lateBoundElementAccessAssignmentDeclarations.ts, 0, 0), Decl(lateBoundElementAccessAssignmentDeclarations.ts, 0, 24), Decl(lateBoundElementAccessAssignmentDeclarations.ts, 2, 26), Decl(lateBoundElementAccessAssignmentDeclarations.ts, 4, 28), Decl(lateBoundElementAccessAssignmentDeclarations.ts, 6, 36) ... and 1 more)
>numMem : Symbol(numMem, Decl(lateBoundElementAccessAssignmentDeclarations.ts, 8, 5))
const a: string = foo[dashStrMem];
>a : Symbol(a, Decl(lateBoundElementAccessAssignmentDeclarations.ts, 14, 5))
>foo : Symbol(foo, Decl(lateBoundElementAccessAssignmentDeclarations.ts, 0, 0), Decl(lateBoundElementAccessAssignmentDeclarations.ts, 0, 24), Decl(lateBoundElementAccessAssignmentDeclarations.ts, 2, 26), Decl(lateBoundElementAccessAssignmentDeclarations.ts, 4, 28), Decl(lateBoundElementAccessAssignmentDeclarations.ts, 6, 36) ... and 1 more)
>dashStrMem : Symbol(dashStrMem, Decl(lateBoundElementAccessAssignmentDeclarations.ts, 6, 5))

View File

@ -0,0 +1,80 @@
=== tests/cases/compiler/lateBoundElementAccessAssignmentDeclarations.ts ===
export function foo() {}
>foo : typeof foo
foo.bar = 12;
>foo.bar = 12 : 12
>foo.bar : number
>foo : typeof foo
>bar : number
>12 : 12
const _private = Symbol();
>_private : unique symbol
>Symbol() : unique symbol
>Symbol : SymbolConstructor
foo[_private] = "ok";
>foo[_private] = "ok" : "ok"
>foo[_private] : string
>foo : typeof foo
>_private : unique symbol
>"ok" : "ok"
const strMem = "strMemName";
>strMem : "strMemName"
>"strMemName" : "strMemName"
foo[strMem] = "ok";
>foo[strMem] = "ok" : "ok"
>foo[strMem] : string
>foo : typeof foo
>strMem : "strMemName"
>"ok" : "ok"
const dashStrMem = "dashed-str-mem";
>dashStrMem : "dashed-str-mem"
>"dashed-str-mem" : "dashed-str-mem"
foo[dashStrMem] = "ok";
>foo[dashStrMem] = "ok" : "ok"
>foo[dashStrMem] : string
>foo : typeof foo
>dashStrMem : "dashed-str-mem"
>"ok" : "ok"
const numMem = 42;
>numMem : 42
>42 : 42
foo[numMem] = "ok";
>foo[numMem] = "ok" : "ok"
>foo[numMem] : string
>foo : typeof foo
>numMem : 42
>"ok" : "ok"
const x: string = foo[_private];
>x : string
>foo[_private] : string
>foo : typeof foo
>_private : unique symbol
const y: string = foo[strMem];
>y : string
>foo[strMem] : string
>foo : typeof foo
>strMem : "strMemName"
const z: string = foo[numMem];
>z : string
>foo[numMem] : string
>foo : typeof foo
>numMem : 42
const a: string = foo[dashStrMem];
>a : string
>foo[dashStrMem] : string
>foo : typeof foo
>dashStrMem : "dashed-str-mem"

View File

@ -0,0 +1,29 @@
//// [file.js]
export function foo() {}
foo.bar = 12;
const _private = Symbol();
foo[_private] = "ok";
const strMem = "strMemName";
foo[strMem] = "ok";
const dashStrMem = "dashed-str-mem";
foo[dashStrMem] = "ok";
const numMem = 42;
foo[numMem] = "ok";
/** @type {string} */
const x = foo[_private];
/** @type {string} */
const y = foo[strMem];
/** @type {string} */
const z = foo[numMem];
/** @type {string} */
const a = foo[dashStrMem];
//// [file.d.ts]
export function foo(): void;
export namespace foo {
export const bar: number;
export const strMemName: string;
}

View File

@ -0,0 +1,62 @@
=== tests/cases/compiler/file.js ===
export function foo() {}
>foo : Symbol(foo, Decl(file.js, 0, 0), Decl(file.js, 0, 24), Decl(file.js, 2, 26), Decl(file.js, 4, 28), Decl(file.js, 6, 36) ... and 1 more)
foo.bar = 12;
>foo.bar : Symbol(foo.bar, Decl(file.js, 0, 24))
>foo : Symbol(foo, Decl(file.js, 0, 0), Decl(file.js, 0, 24), Decl(file.js, 2, 26), Decl(file.js, 4, 28), Decl(file.js, 6, 36) ... and 1 more)
>bar : Symbol(foo.bar, Decl(file.js, 0, 24))
const _private = Symbol();
>_private : Symbol(_private, Decl(file.js, 2, 5))
>Symbol : Symbol(Symbol, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --))
foo[_private] = "ok";
>foo : Symbol(foo, Decl(file.js, 0, 0), Decl(file.js, 0, 24), Decl(file.js, 2, 26), Decl(file.js, 4, 28), Decl(file.js, 6, 36) ... and 1 more)
>_private : Symbol(_private, Decl(file.js, 2, 5))
const strMem = "strMemName";
>strMem : Symbol(strMem, Decl(file.js, 4, 5))
foo[strMem] = "ok";
>foo : Symbol(foo, Decl(file.js, 0, 0), Decl(file.js, 0, 24), Decl(file.js, 2, 26), Decl(file.js, 4, 28), Decl(file.js, 6, 36) ... and 1 more)
>strMem : Symbol(strMem, Decl(file.js, 4, 5))
const dashStrMem = "dashed-str-mem";
>dashStrMem : Symbol(dashStrMem, Decl(file.js, 6, 5))
foo[dashStrMem] = "ok";
>foo : Symbol(foo, Decl(file.js, 0, 0), Decl(file.js, 0, 24), Decl(file.js, 2, 26), Decl(file.js, 4, 28), Decl(file.js, 6, 36) ... and 1 more)
>dashStrMem : Symbol(dashStrMem, Decl(file.js, 6, 5))
const numMem = 42;
>numMem : Symbol(numMem, Decl(file.js, 8, 5))
foo[numMem] = "ok";
>foo : Symbol(foo, Decl(file.js, 0, 0), Decl(file.js, 0, 24), Decl(file.js, 2, 26), Decl(file.js, 4, 28), Decl(file.js, 6, 36) ... and 1 more)
>numMem : Symbol(numMem, Decl(file.js, 8, 5))
/** @type {string} */
const x = foo[_private];
>x : Symbol(x, Decl(file.js, 12, 5))
>foo : Symbol(foo, Decl(file.js, 0, 0), Decl(file.js, 0, 24), Decl(file.js, 2, 26), Decl(file.js, 4, 28), Decl(file.js, 6, 36) ... and 1 more)
>_private : Symbol(_private, Decl(file.js, 2, 5))
/** @type {string} */
const y = foo[strMem];
>y : Symbol(y, Decl(file.js, 14, 5))
>foo : Symbol(foo, Decl(file.js, 0, 0), Decl(file.js, 0, 24), Decl(file.js, 2, 26), Decl(file.js, 4, 28), Decl(file.js, 6, 36) ... and 1 more)
>strMem : Symbol(strMem, Decl(file.js, 4, 5))
/** @type {string} */
const z = foo[numMem];
>z : Symbol(z, Decl(file.js, 16, 5))
>foo : Symbol(foo, Decl(file.js, 0, 0), Decl(file.js, 0, 24), Decl(file.js, 2, 26), Decl(file.js, 4, 28), Decl(file.js, 6, 36) ... and 1 more)
>numMem : Symbol(numMem, Decl(file.js, 8, 5))
/** @type {string} */
const a = foo[dashStrMem];
>a : Symbol(a, Decl(file.js, 18, 5))
>foo : Symbol(foo, Decl(file.js, 0, 0), Decl(file.js, 0, 24), Decl(file.js, 2, 26), Decl(file.js, 4, 28), Decl(file.js, 6, 36) ... and 1 more)
>dashStrMem : Symbol(dashStrMem, Decl(file.js, 6, 5))

View File

@ -0,0 +1,84 @@
=== tests/cases/compiler/file.js ===
export function foo() {}
>foo : typeof foo
foo.bar = 12;
>foo.bar = 12 : 12
>foo.bar : number
>foo : typeof foo
>bar : number
>12 : 12
const _private = Symbol();
>_private : unique symbol
>Symbol() : unique symbol
>Symbol : SymbolConstructor
foo[_private] = "ok";
>foo[_private] = "ok" : "ok"
>foo[_private] : string
>foo : typeof foo
>_private : unique symbol
>"ok" : "ok"
const strMem = "strMemName";
>strMem : "strMemName"
>"strMemName" : "strMemName"
foo[strMem] = "ok";
>foo[strMem] = "ok" : "ok"
>foo[strMem] : string
>foo : typeof foo
>strMem : "strMemName"
>"ok" : "ok"
const dashStrMem = "dashed-str-mem";
>dashStrMem : "dashed-str-mem"
>"dashed-str-mem" : "dashed-str-mem"
foo[dashStrMem] = "ok";
>foo[dashStrMem] = "ok" : "ok"
>foo[dashStrMem] : string
>foo : typeof foo
>dashStrMem : "dashed-str-mem"
>"ok" : "ok"
const numMem = 42;
>numMem : 42
>42 : 42
foo[numMem] = "ok";
>foo[numMem] = "ok" : "ok"
>foo[numMem] : string
>foo : typeof foo
>numMem : 42
>"ok" : "ok"
/** @type {string} */
const x = foo[_private];
>x : string
>foo[_private] : string
>foo : typeof foo
>_private : unique symbol
/** @type {string} */
const y = foo[strMem];
>y : string
>foo[strMem] : string
>foo : typeof foo
>strMem : "strMemName"
/** @type {string} */
const z = foo[numMem];
>z : string
>foo[numMem] : string
>foo : typeof foo
>numMem : 42
/** @type {string} */
const a = foo[dashStrMem];
>a : string
>foo[dashStrMem] : string
>foo : typeof foo
>dashStrMem : "dashed-str-mem"

View File

@ -0,0 +1,18 @@
// @strict: true
// @declaration: true
// @target: es6
export function foo() {}
foo.bar = 12;
const _private = Symbol();
foo[_private] = "ok";
const strMem = "strMemName";
foo[strMem] = "ok";
const dashStrMem = "dashed-str-mem";
foo[dashStrMem] = "ok";
const numMem = 42;
foo[numMem] = "ok";
const x: string = foo[_private];
const y: string = foo[strMem];
const z: string = foo[numMem];
const a: string = foo[dashStrMem];

View File

@ -0,0 +1,26 @@
// @strict: true
// @declaration: true
// @target: es6
// @checkJs: true
// @allowJs: true
// @emitDeclarationOnly: true
// @filename: file.js
export function foo() {}
foo.bar = 12;
const _private = Symbol();
foo[_private] = "ok";
const strMem = "strMemName";
foo[strMem] = "ok";
const dashStrMem = "dashed-str-mem";
foo[dashStrMem] = "ok";
const numMem = 42;
foo[numMem] = "ok";
/** @type {string} */
const x = foo[_private];
/** @type {string} */
const y = foo[strMem];
/** @type {string} */
const z = foo[numMem];
/** @type {string} */
const a = foo[dashStrMem];