Skip to content

Commit a04bfff

Browse files
authored
Merge pull request #32 from mheiber/private-named-instance-fields
Private-named instance fields
2 parents 9e28a81 + 3f6b68f commit a04bfff

File tree

219 files changed

+6649
-1126
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

219 files changed

+6649
-1126
lines changed

src/compiler/binder.ts

+44-22
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,16 @@ namespace ts {
278278
Debug.assert(isWellKnownSymbolSyntactically(nameExpression));
279279
return getPropertyNameForKnownSymbolName(idText((<PropertyAccessExpression>nameExpression).name));
280280
}
281+
if (isPrivateName(name)) {
282+
// containingClass exists because private names only allowed inside classes
283+
const containingClass = getContainingClass(name.parent);
284+
if (!containingClass) {
285+
// we're in a case where there's a private name outside a class (invalid)
286+
return undefined;
287+
}
288+
const containingClassSymbol = containingClass.symbol;
289+
return getPropertyNameForPrivateNameDescription(containingClassSymbol, name.escapedText);
290+
}
281291
return isPropertyNameLiteral(name) ? getEscapedTextOfIdentifierOrLiteral(name) : undefined;
282292
}
283293
switch (node.kind) {
@@ -334,6 +344,10 @@ namespace ts {
334344

335345
const isDefaultExport = hasModifier(node, ModifierFlags.Default);
336346

347+
// need this before getDeclarationName
348+
if (isNamedDeclaration(node)) {
349+
node.name.parent = node;
350+
}
337351
// The exported symbol for an export default function/class node is always named "default"
338352
const name = isDefaultExport && parent ? InternalSymbolName.Default : getDeclarationName(node);
339353

@@ -386,11 +400,6 @@ namespace ts {
386400
symbolTable.set(name, symbol = createSymbol(SymbolFlags.None, name));
387401
}
388402
else if (!(includes & SymbolFlags.Variable && symbol.flags & SymbolFlags.Assignment)) {
389-
// Assignment declarations are allowed to merge with variables, no matter what other flags they have.
390-
if (isNamedDeclaration(node)) {
391-
node.name.parent = node;
392-
}
393-
394403
// Report errors every position with duplicate declaration
395404
// Report errors on previous encountered declarations
396405
let message = symbol.flags & SymbolFlags.BlockScopedVariable
@@ -1458,7 +1467,7 @@ namespace ts {
14581467
}
14591468
if (node.expression.kind === SyntaxKind.PropertyAccessExpression) {
14601469
const propertyAccess = <PropertyAccessExpression>node.expression;
1461-
if (isNarrowableOperand(propertyAccess.expression) && isPushOrUnshiftIdentifier(propertyAccess.name)) {
1470+
if (isIdentifier(propertyAccess.name) && isNarrowableOperand(propertyAccess.expression) && isPushOrUnshiftIdentifier(propertyAccess.name)) {
14621471
currentFlow = createFlowArrayMutation(currentFlow, node);
14631472
}
14641473
}
@@ -1855,6 +1864,18 @@ namespace ts {
18551864
return Diagnostics.Identifier_expected_0_is_a_reserved_word_in_strict_mode;
18561865
}
18571866

1867+
// The binder visits every node, so this is a good place to check for
1868+
// the reserved private name (there is only one)
1869+
function checkPrivateName(node: PrivateName) {
1870+
if (node.escapedText === "#constructor") {
1871+
// Report error only if there are no parse errors in file
1872+
if (!file.parseDiagnostics.length) {
1873+
file.bindDiagnostics.push(createDiagnosticForNode(node,
1874+
Diagnostics.constructor_is_a_reserved_word, declarationNameToString(node)));
1875+
}
1876+
}
1877+
}
1878+
18581879
function checkStrictModeBinaryExpression(node: BinaryExpression) {
18591880
if (inStrictMode && isLeftHandSideExpression(node.left) && isAssignmentOperator(node.operatorToken.kind)) {
18601881
// ECMA 262 (Annex C) The identifier eval or arguments may not appear as the LeftHandSideExpression of an
@@ -2127,6 +2148,8 @@ namespace ts {
21272148
node.flowNode = currentFlow;
21282149
}
21292150
return checkStrictModeIdentifier(<Identifier>node);
2151+
case SyntaxKind.PrivateName:
2152+
return checkPrivateName(node as PrivateName);
21302153
case SyntaxKind.PropertyAccessExpression:
21312154
case SyntaxKind.ElementAccessExpression:
21322155
if (currentFlow && isNarrowableReference(<Expression>node)) {
@@ -2424,7 +2447,7 @@ namespace ts {
24242447
if (!setCommonJsModuleIndicator(node)) {
24252448
return;
24262449
}
2427-
const symbol = forEachIdentifierInEntityName(node.arguments[0], /*parent*/ undefined, (id, symbol) => {
2450+
const symbol = forEachIdentifierOrPrivateNameInEntityName(node.arguments[0], /*parent*/ undefined, (id, symbol) => {
24282451
if (symbol) {
24292452
addDeclarationToSymbol(symbol, id, SymbolFlags.Module | SymbolFlags.Assignment);
24302453
}
@@ -2443,7 +2466,7 @@ namespace ts {
24432466
return;
24442467
}
24452468
const lhs = node.left as PropertyAccessEntityNameExpression;
2446-
const symbol = forEachIdentifierInEntityName(lhs.expression, /*parent*/ undefined, (id, symbol) => {
2469+
const symbol = forEachIdentifierOrPrivateNameInEntityName(lhs.expression, /*parent*/ undefined, (id, symbol) => {
24472470
if (symbol) {
24482471
addDeclarationToSymbol(symbol, id, SymbolFlags.Module | SymbolFlags.Assignment);
24492472
}
@@ -2613,7 +2636,7 @@ namespace ts {
26132636
// make symbols or add declarations for intermediate containers
26142637
const flags = SymbolFlags.Module | SymbolFlags.Assignment;
26152638
const excludeFlags = SymbolFlags.ValueModuleExcludes & ~SymbolFlags.Assignment;
2616-
namespaceSymbol = forEachIdentifierInEntityName(entityName, namespaceSymbol, (id, symbol, parent) => {
2639+
namespaceSymbol = forEachIdentifierOrPrivateNameInEntityName(entityName, namespaceSymbol, (id, symbol, parent) => {
26172640
if (symbol) {
26182641
addDeclarationToSymbol(symbol, id, flags);
26192642
return symbol;
@@ -2701,15 +2724,15 @@ namespace ts {
27012724
}
27022725
}
27032726

2704-
function forEachIdentifierInEntityName(e: EntityNameExpression, parent: Symbol | undefined, action: (e: Identifier, symbol: Symbol | undefined, parent: Symbol | undefined) => Symbol | undefined): Symbol | undefined {
2727+
function forEachIdentifierOrPrivateNameInEntityName(e: EntityNameExpression, parent: Symbol | undefined, action: (e: Identifier | PrivateName, symbol: Symbol | undefined, parent: Symbol | undefined) => Symbol | undefined): Symbol | undefined {
27052728
if (isExportsOrModuleExportsOrAlias(file, e)) {
27062729
return file.symbol;
27072730
}
27082731
else if (isIdentifier(e)) {
27092732
return action(e, lookupSymbolForPropertyAccess(e), parent);
27102733
}
27112734
else {
2712-
const s = forEachIdentifierInEntityName(e.expression, parent, action);
2735+
const s = forEachIdentifierOrPrivateNameInEntityName(e.expression, parent, action);
27132736
if (!s || !s.exports) return Debug.fail();
27142737
return action(e.name, s.exports.get(e.name.escapedText), s);
27152738
}
@@ -3231,8 +3254,7 @@ namespace ts {
32313254
// A ClassDeclaration is ES6 syntax.
32323255
transformFlags = subtreeFlags | TransformFlags.AssertES2015;
32333256

3234-
// A class with a parameter property assignment, property initializer, computed property name, or decorator is
3235-
// TypeScript syntax.
3257+
// A class with a parameter property assignment or decorator is TypeScript syntax.
32363258
// An exported declaration may be TypeScript syntax, but is handled by the visitor
32373259
// for a namespace declaration.
32383260
if ((subtreeFlags & TransformFlags.ContainsTypeScriptClassSyntax)
@@ -3249,8 +3271,7 @@ namespace ts {
32493271
// A ClassExpression is ES6 syntax.
32503272
let transformFlags = subtreeFlags | TransformFlags.AssertES2015;
32513273

3252-
// A class with a parameter property assignment, property initializer, or decorator is
3253-
// TypeScript syntax.
3274+
// A class with a parameter property assignment or decorator is TypeScript syntax.
32543275
if (subtreeFlags & TransformFlags.ContainsTypeScriptClassSyntax
32553276
|| node.typeParameters) {
32563277
transformFlags |= TransformFlags.AssertTypeScript;
@@ -3340,7 +3361,6 @@ namespace ts {
33403361
|| hasModifier(node, ModifierFlags.TypeScriptModifier)
33413362
|| node.typeParameters
33423363
|| node.type
3343-
|| (node.name && isComputedPropertyName(node.name)) // While computed method names aren't typescript, the TS transform must visit them to emit property declarations correctly
33443364
|| !node.body) {
33453365
transformFlags |= TransformFlags.AssertTypeScript;
33463366
}
@@ -3371,7 +3391,6 @@ namespace ts {
33713391
if (node.decorators
33723392
|| hasModifier(node, ModifierFlags.TypeScriptModifier)
33733393
|| node.type
3374-
|| (node.name && isComputedPropertyName(node.name)) // While computed accessor names aren't typescript, the TS transform must visit them to emit property declarations correctly
33753394
|| !node.body) {
33763395
transformFlags |= TransformFlags.AssertTypeScript;
33773396
}
@@ -3386,12 +3405,15 @@ namespace ts {
33863405
}
33873406

33883407
function computePropertyDeclaration(node: PropertyDeclaration, subtreeFlags: TransformFlags) {
3389-
// A PropertyDeclaration is TypeScript syntax.
3390-
let transformFlags = subtreeFlags | TransformFlags.AssertTypeScript;
3408+
let transformFlags = subtreeFlags;
3409+
3410+
// Decorators, TypeScript-specific modifiers, and type annotations are TypeScript syntax.
3411+
if (some(node.decorators) || hasModifier(node, ModifierFlags.TypeScriptModifier) || node.type) {
3412+
transformFlags |= TransformFlags.AssertTypeScript;
3413+
}
33913414

3392-
// If the PropertyDeclaration has an initializer or a computed name, we need to inform its ancestor
3393-
// so that it handle the transformation.
3394-
if (node.initializer || isComputedPropertyName(node.name)) {
3415+
// Hoisted variables related to class properties should live within the TypeScript class wrapper.
3416+
if (isComputedPropertyName(node.name) || (hasStaticModifier(node) && node.initializer)) {
33953417
transformFlags |= TransformFlags.ContainsTypeScriptClassSyntax;
33963418
}
33973419

0 commit comments

Comments
 (0)