@@ -90,7 +90,8 @@ module ts {
90
90
getAugmentedPropertiesOfApparentType : getAugmentedPropertiesOfApparentType ,
91
91
getRootSymbol : getRootSymbol ,
92
92
getContextualType : getContextualType ,
93
- getFullyQualifiedName : getFullyQualifiedName
93
+ getFullyQualifiedName : getFullyQualifiedName ,
94
+ getEnumMemberValue : getEnumMemberValue
94
95
} ;
95
96
96
97
var undefinedSymbol = createSymbol ( SymbolFlags . Property | SymbolFlags . Transient , "undefined" ) ;
@@ -6495,7 +6496,7 @@ module ts {
6495
6496
}
6496
6497
}
6497
6498
6498
- function getConstantValue ( node : Expression ) : number {
6499
+ function getConstantValueForExpression ( node : Expression ) : number {
6499
6500
var isNegative = false ;
6500
6501
if ( node . kind === SyntaxKind . PrefixOperator ) {
6501
6502
var unaryExpression = < UnaryExpression > node ;
@@ -6512,45 +6513,63 @@ module ts {
6512
6513
return undefined ;
6513
6514
}
6514
6515
6516
+ function computeEnumMemberValues ( node : EnumDeclaration , reportErrors : boolean ) {
6517
+ var nodeLinks = getNodeLinks ( node ) ;
6518
+
6519
+ if ( ! ( nodeLinks . flags & NodeCheckFlags . EnumValuesComputedAndChecked ) ) {
6520
+ var enumSymbol = getSymbolOfNode ( node ) ;
6521
+ var enumType = getDeclaredTypeOfSymbol ( enumSymbol ) ;
6522
+ var autoValue = 0 ;
6523
+ var ambient = isInAmbientContext ( node ) ;
6524
+
6525
+ forEach ( node . members , member => {
6526
+ var initializer = member . initializer ;
6527
+ if ( initializer ) {
6528
+ autoValue = getConstantValueForExpression ( initializer ) ;
6529
+ if ( autoValue === undefined && ! ambient ) {
6530
+ // Only here do we need to check that the initializer is assignable to the enum type.
6531
+ // If it is a constant value (not undefined), it is syntactically constrained to be a number.
6532
+ // Also, we do not need to check this for ambients because there is already
6533
+ // a syntax error if it is not a constant.
6534
+ if ( reportErrors ) {
6535
+ checkTypeAssignableTo ( checkExpression ( initializer ) , enumType , initializer , /*chainedMessage*/ undefined , /*terminalMessage*/ undefined ) ;
6536
+ }
6537
+ }
6538
+ }
6539
+ else if ( ambient ) {
6540
+ autoValue = undefined ;
6541
+ }
6542
+
6543
+ if ( autoValue !== undefined ) {
6544
+ getNodeLinks ( member ) . enumMemberValue = autoValue ++ ;
6545
+ }
6546
+ } ) ;
6547
+
6548
+ if ( reportErrors ) {
6549
+ nodeLinks . flags |= NodeCheckFlags . EnumValuesComputedAndChecked ;
6550
+ }
6551
+ }
6552
+ }
6553
+
6515
6554
function checkEnumDeclaration ( node : EnumDeclaration ) {
6516
6555
if ( ! fullTypeCheck ) {
6517
6556
return ;
6518
6557
}
6558
+
6519
6559
checkTypeNameIsReserved ( node . name , Diagnostics . Enum_name_cannot_be_0 ) ;
6520
6560
checkCollisionWithCapturedThisVariable ( node , node . name ) ;
6521
6561
checkCollistionWithRequireExportsInGeneratedCode ( node , node . name ) ;
6522
6562
checkExportsOnMergedDeclarations ( node ) ;
6523
- var enumSymbol = getSymbolOfNode ( node ) ;
6524
- var enumType = getDeclaredTypeOfSymbol ( enumSymbol ) ;
6525
- var autoValue = 0 ;
6526
- var ambient = isInAmbientContext ( node ) ;
6527
- forEach ( node . members , member => {
6528
- var initializer = member . initializer ;
6529
- if ( initializer ) {
6530
- autoValue = getConstantValue ( initializer ) ;
6531
- if ( autoValue === undefined && ! ambient ) {
6532
- // Only here do we need to check that the initializer is assignable to the enum type.
6533
- // If it is a constant value (not undefined), it is syntactically constrained to be a number.
6534
- // Also, we do not need to check this for ambients because there is already
6535
- // a syntax error if it is not a constant.
6536
- checkTypeAssignableTo ( checkExpression ( initializer ) , enumType , initializer , /*chainedMessage*/ undefined , /*terminalMessage*/ undefined ) ;
6537
- }
6538
- }
6539
- else if ( ambient ) {
6540
- autoValue = undefined ;
6541
- }
6542
6563
6543
- if ( autoValue !== undefined ) {
6544
- getNodeLinks ( member ) . enumMemberValue = autoValue ++ ;
6545
- }
6546
- } ) ;
6564
+ computeEnumMemberValues ( node , /*reportErrors:*/ true ) ;
6547
6565
6548
6566
// Spec 2014 - Section 9.3:
6549
6567
// It isn't possible for one enum declaration to continue the automatic numbering sequence of another,
6550
6568
// and when an enum type has multiple declarations, only one declaration is permitted to omit a value
6551
6569
// for the first member.
6552
6570
//
6553
6571
// Only perform this check once per symbol
6572
+ var enumSymbol = getSymbolOfNode ( node ) ;
6554
6573
var firstDeclaration = getDeclarationOfKind ( enumSymbol , node . kind ) ;
6555
6574
if ( node === firstDeclaration ) {
6556
6575
var seenEnumMissingInitialInitializer = false ;
@@ -7450,17 +7469,6 @@ module ts {
7450
7469
}
7451
7470
}
7452
7471
7453
- function getPropertyAccessSubstitution ( node : PropertyAccess ) : string {
7454
- var symbol = getNodeLinks ( node ) . resolvedSymbol ;
7455
- if ( symbol && ( symbol . flags & SymbolFlags . EnumMember ) ) {
7456
- var declaration = symbol . valueDeclaration ;
7457
- var constantValue : number ;
7458
- if ( declaration . kind === SyntaxKind . EnumMember && ( constantValue = getNodeLinks ( declaration ) . enumMemberValue ) !== undefined ) {
7459
- return constantValue . toString ( ) + " /* " + identifierToString ( declaration . name ) + " */" ;
7460
- }
7461
- }
7462
- }
7463
-
7464
7472
function getExportAssignmentName ( node : SourceFile ) : string {
7465
7473
var symbol = getExportAssignmentSymbol ( getSymbolOfNode ( node ) ) ;
7466
7474
return symbol && symbolIsValue ( symbol ) ? symbolToString ( symbol ) : undefined ;
@@ -7523,9 +7531,23 @@ module ts {
7523
7531
}
7524
7532
7525
7533
function getEnumMemberValue ( node : EnumMember ) : number {
7534
+ computeEnumMemberValues ( < EnumDeclaration > node . parent , /*reportErrors:*/ false ) ;
7526
7535
return getNodeLinks ( node ) . enumMemberValue ;
7527
7536
}
7528
7537
7538
+ function getConstantValue ( node : PropertyAccess ) : number {
7539
+ var symbol = getNodeLinks ( node ) . resolvedSymbol ;
7540
+ if ( symbol && ( symbol . flags & SymbolFlags . EnumMember ) ) {
7541
+ var declaration = symbol . valueDeclaration ;
7542
+ var constantValue : number ;
7543
+ if ( declaration . kind === SyntaxKind . EnumMember && ( constantValue = getNodeLinks ( declaration ) . enumMemberValue ) !== undefined ) {
7544
+ return constantValue ;
7545
+ }
7546
+ }
7547
+
7548
+ return undefined ;
7549
+ }
7550
+
7529
7551
// Create a single instance that we can wrap the underlying emitter TextWriter with. That
7530
7552
// way we don't have to allocate a new wrapper every time writeTypeAtLocation and
7531
7553
// writeReturnTypeOfSignatureDeclaration are called.
@@ -7561,7 +7583,6 @@ module ts {
7561
7583
getProgram : ( ) => program ,
7562
7584
getLocalNameOfContainer : getLocalNameOfContainer ,
7563
7585
getExpressionNamePrefix : getExpressionNamePrefix ,
7564
- getPropertyAccessSubstitution : getPropertyAccessSubstitution ,
7565
7586
getExportAssignmentName : getExportAssignmentName ,
7566
7587
isReferencedImportDeclaration : isReferencedImportDeclaration ,
7567
7588
getNodeCheckFlags : getNodeCheckFlags ,
@@ -7573,7 +7594,8 @@ module ts {
7573
7594
writeTypeAtLocation : writeTypeAtLocation ,
7574
7595
writeReturnTypeOfSignatureDeclaration : writeReturnTypeOfSignatureDeclaration ,
7575
7596
isSymbolAccessible : isSymbolAccessible ,
7576
- isImportDeclarationEntityNameReferenceDeclarationVisibile : isImportDeclarationEntityNameReferenceDeclarationVisibile
7597
+ isImportDeclarationEntityNameReferenceDeclarationVisibile : isImportDeclarationEntityNameReferenceDeclarationVisibile ,
7598
+ getConstantValue : getConstantValue ,
7577
7599
} ;
7578
7600
checkProgram ( ) ;
7579
7601
return emitFiles ( resolver , targetSourceFile ) ;
0 commit comments