Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30498,10 +30498,37 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
function markIdentifierAliasReferenced(location: Identifier) {
const symbol = getResolvedSymbol(location);
if (symbol && symbol !== argumentsSymbol && symbol !== unknownSymbol && !isThisInTypeQuery(location)) {
// Check if this identifier is in a computed property name of an abstract method/property
// If so, we should not mark it as referenced since abstract members are not emitted
if (isIdentifierInAbstractMemberComputedPropertyName(location)) {
return;
}
markAliasReferenced(symbol, location);
}
}

function isIdentifierInAbstractMemberComputedPropertyName(node: Identifier): boolean {
// Walk up the AST to see if this identifier is within a computed property name
let parent = node.parent;
while (parent) {
if (isComputedPropertyName(parent)) {
// Found a computed property name, now check if it's for an abstract member
const memberParent = parent.parent;
if (
(isMethodDeclaration(memberParent) || isMethodSignature(memberParent) ||
isPropertyDeclaration(memberParent) || isPropertySignature(memberParent)) &&
hasSyntacticModifier(memberParent, ModifierFlags.Abstract)
) {
return true;
}
// If we found a computed property name but it's not for an abstract member, stop searching
return false;
}
parent = parent.parent;
}
return false;
}

function markPropertyAliasReferenced(location: PropertyAccessExpression | QualifiedName, propSymbol?: Symbol, parentType?: Type) {
const left = isPropertyAccessExpression(location) ? location.expression : location.left;
if (isThisIdentifier(left) || !isIdentifier(left)) {
Expand Down
27 changes: 27 additions & 0 deletions tests/baselines/reference/abstractMethodComputedPropertyElision.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//// [tests/cases/compiler/abstractMethodComputedPropertyElision.ts] ////

//// [sharedSymbol.ts]
export const sharedSymbol: unique symbol = Symbol();

//// [AbstractClassWithTypeImports.ts]
import type { sharedSymbol } from "./sharedSymbol.js";

export abstract class AbstractClassTypeImport {
public abstract [sharedSymbol]: string;
}

//// [AbstractClassNormalImports.ts]
import { sharedSymbol } from "./sharedSymbol.js";

export abstract class AbstractClassNormalImport {
public abstract [sharedSymbol]: string;
}

//// [sharedSymbol.js]
export const sharedSymbol = Symbol();
//// [AbstractClassWithTypeImports.js]
export class AbstractClassTypeImport {
}
//// [AbstractClassNormalImports.js]
export class AbstractClassNormalImport {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//// [tests/cases/compiler/abstractMethodComputedPropertyElision.ts] ////

=== sharedSymbol.ts ===
export const sharedSymbol: unique symbol = Symbol();
>sharedSymbol : Symbol(sharedSymbol, Decl(sharedSymbol.ts, 0, 12))
>Symbol : Symbol(Symbol, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2019.symbol.d.ts, --, --))

=== AbstractClassWithTypeImports.ts ===
import type { sharedSymbol } from "./sharedSymbol.js";
>sharedSymbol : Symbol(sharedSymbol, Decl(AbstractClassWithTypeImports.ts, 0, 13))

export abstract class AbstractClassTypeImport {
>AbstractClassTypeImport : Symbol(AbstractClassTypeImport, Decl(AbstractClassWithTypeImports.ts, 0, 54))

public abstract [sharedSymbol]: string;
>[sharedSymbol] : Symbol(AbstractClassTypeImport[sharedSymbol], Decl(AbstractClassWithTypeImports.ts, 2, 47))
>sharedSymbol : Symbol(sharedSymbol, Decl(AbstractClassWithTypeImports.ts, 0, 13))
}

=== AbstractClassNormalImports.ts ===
import { sharedSymbol } from "./sharedSymbol.js";
>sharedSymbol : Symbol(sharedSymbol, Decl(AbstractClassNormalImports.ts, 0, 8))

export abstract class AbstractClassNormalImport {
>AbstractClassNormalImport : Symbol(AbstractClassNormalImport, Decl(AbstractClassNormalImports.ts, 0, 49))

public abstract [sharedSymbol]: string;
>[sharedSymbol] : Symbol(AbstractClassNormalImport[sharedSymbol], Decl(AbstractClassNormalImports.ts, 2, 49))
>sharedSymbol : Symbol(sharedSymbol, Decl(AbstractClassNormalImports.ts, 0, 8))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//// [tests/cases/compiler/abstractMethodComputedPropertyElision.ts] ////

=== sharedSymbol.ts ===
export const sharedSymbol: unique symbol = Symbol();
>sharedSymbol : unique symbol
> : ^^^^^^^^^^^^^
>Symbol() : unique symbol
> : ^^^^^^^^^^^^^
>Symbol : SymbolConstructor
> : ^^^^^^^^^^^^^^^^^

=== AbstractClassWithTypeImports.ts ===
import type { sharedSymbol } from "./sharedSymbol.js";
>sharedSymbol : any
> : ^^^

export abstract class AbstractClassTypeImport {
>AbstractClassTypeImport : AbstractClassTypeImport
> : ^^^^^^^^^^^^^^^^^^^^^^^

public abstract [sharedSymbol]: string;
>[sharedSymbol] : string
> : ^^^^^^
>sharedSymbol : unique symbol
> : ^^^^^^^^^^^^^
}

=== AbstractClassNormalImports.ts ===
import { sharedSymbol } from "./sharedSymbol.js";
>sharedSymbol : unique symbol
> : ^^^^^^^^^^^^^

export abstract class AbstractClassNormalImport {
>AbstractClassNormalImport : AbstractClassNormalImport
> : ^^^^^^^^^^^^^^^^^^^^^^^^^

public abstract [sharedSymbol]: string;
>[sharedSymbol] : string
> : ^^^^^^
>sharedSymbol : unique symbol
> : ^^^^^^^^^^^^^
}
19 changes: 19 additions & 0 deletions tests/cases/compiler/abstractMethodComputedPropertyElision.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// @module: esnext
// @target: esnext

// @Filename: sharedSymbol.ts
export const sharedSymbol: unique symbol = Symbol();

// @Filename: AbstractClassWithTypeImports.ts
import type { sharedSymbol } from "./sharedSymbol.js";

export abstract class AbstractClassTypeImport {
public abstract [sharedSymbol]: string;
}

// @Filename: AbstractClassNormalImports.ts
import { sharedSymbol } from "./sharedSymbol.js";

export abstract class AbstractClassNormalImport {
public abstract [sharedSymbol]: string;
}