@@ -306,6 +306,22 @@ module ts {
306
306
// return undefined if we can't find a symbol.
307
307
}
308
308
309
+ /** Returns true if node1 is defined before node 2**/
310
+ function isDefinedBefore ( node1 : Node , node2 : Node ) : boolean {
311
+ var file1 = getSourceFileOfNode ( node1 ) ;
312
+ var file2 = getSourceFileOfNode ( node2 ) ;
313
+ if ( file1 === file2 ) {
314
+ return node1 . pos <= node2 . pos ;
315
+ }
316
+
317
+ if ( ! compilerOptions . out ) {
318
+ return true ;
319
+ }
320
+
321
+ var sourceFiles = program . getSourceFiles ( ) ;
322
+ return sourceFiles . indexOf ( file1 ) <= sourceFiles . indexOf ( file2 ) ;
323
+ }
324
+
309
325
function resolveName ( location : Node , name : string , meaning : SymbolFlags , nameNotFoundMessage : DiagnosticMessage , nameArg : string ) : Symbol {
310
326
var errorLocation = location ;
311
327
var result : Symbol ;
@@ -330,18 +346,8 @@ module ts {
330
346
// Block-scoped variables can not be used before their definition
331
347
var declaration = forEach ( s . declarations , d => d . flags & NodeFlags . BlockScoped ? d : undefined ) ;
332
348
Debug . assert ( declaration , "Block-scoped variable declaration is undefined" ) ;
333
- var declarationSourceFile = getSourceFileOfNode ( declaration ) ;
334
- var referenceSourceFile = getSourceFileOfNode ( errorLocation ) ;
335
- if ( declarationSourceFile === referenceSourceFile ) {
336
- if ( declaration . pos > errorLocation . pos ) {
337
- error ( errorLocation , Diagnostics . Block_scoped_variable_0_used_before_its_declaration , identifierToString ( declaration . name ) ) ;
338
- }
339
- }
340
- else if ( compilerOptions . out ) {
341
- var sourceFiles = program . getSourceFiles ( ) ;
342
- if ( sourceFiles . indexOf ( referenceSourceFile ) < sourceFiles . indexOf ( declarationSourceFile ) ) {
343
- error ( errorLocation , Diagnostics . Block_scoped_variable_0_used_before_its_declaration , identifierToString ( declaration . name ) ) ;
344
- }
349
+ if ( ! isDefinedBefore ( declaration , errorLocation ) ) {
350
+ error ( errorLocation , Diagnostics . Block_scoped_variable_0_used_before_its_declaration , identifierToString ( declaration . name ) ) ;
345
351
}
346
352
}
347
353
return s ;
@@ -489,12 +495,10 @@ module ts {
489
495
}
490
496
491
497
// Resolves a qualified name and any involved import aliases
492
- function resolveEntityName ( location : Node , name : EntityName , meaning : SymbolFlags , suppressErrors ?: boolean ) : Symbol {
498
+ function resolveEntityName ( location : Node , name : EntityName , meaning : SymbolFlags ) : Symbol {
493
499
if ( name . kind === SyntaxKind . Identifier ) {
494
500
// TODO: Investigate error recovery for symbols not found
495
- var nameNotFoundMessage = ! suppressErrors && Diagnostics . Cannot_find_name_0 ;
496
- var nameArg = ! suppressErrors && identifierToString ( < Identifier > name ) ;
497
- var symbol = resolveName ( location , ( < Identifier > name ) . text , meaning , nameNotFoundMessage , nameArg ) ;
501
+ var symbol = resolveName ( location , ( < Identifier > name ) . text , meaning , Diagnostics . Cannot_find_name_0 , identifierToString ( < Identifier > name ) ) ;
498
502
if ( ! symbol ) {
499
503
return ;
500
504
}
@@ -504,10 +508,8 @@ module ts {
504
508
if ( ! namespace || namespace === unknownSymbol || ( < QualifiedName > name ) . right . kind === SyntaxKind . Missing ) return ;
505
509
var symbol = getSymbol ( namespace . exports , ( < QualifiedName > name ) . right . text , meaning ) ;
506
510
if ( ! symbol ) {
507
- if ( ! suppressErrors ) {
508
- error ( location , Diagnostics . Module_0_has_no_exported_member_1 , getFullyQualifiedName ( namespace ) ,
509
- identifierToString ( ( < QualifiedName > name ) . right ) ) ;
510
- }
511
+ error ( location , Diagnostics . Module_0_has_no_exported_member_1 , getFullyQualifiedName ( namespace ) ,
512
+ identifierToString ( ( < QualifiedName > name ) . right ) ) ;
511
513
return ;
512
514
}
513
515
}
@@ -7410,13 +7412,13 @@ module ts {
7410
7412
var autoValue = 0 ;
7411
7413
var ambient = isInAmbientContext ( node ) ;
7412
7414
7413
- forEach ( node . members , member => {
7415
+ forEach ( node . members , member => {
7414
7416
if ( isNumericName ( member . name . text ) ) {
7415
7417
error ( member . name , Diagnostics . An_enum_member_cannot_have_a_numeric_name ) ;
7416
7418
}
7417
7419
var initializer = member . initializer ;
7418
7420
if ( initializer ) {
7419
- autoValue = getConstantValueForEnumMemberInitializer ( member , initializer ) ;
7421
+ autoValue = getConstantValueForEnumMemberInitializer ( initializer ) ;
7420
7422
if ( autoValue === undefined && ! ambient ) {
7421
7423
// Only here do we need to check that the initializer is assignable to the enum type.
7422
7424
// If it is a constant value (not undefined), it is syntactically constrained to be a number.
@@ -7437,66 +7439,101 @@ module ts {
7437
7439
nodeLinks . flags |= NodeCheckFlags . EnumValuesComputed ;
7438
7440
}
7439
7441
7440
- function getConstantValueForEnumMemberInitializer ( member : EnumMember , initializer : Expression ) : number {
7442
+ function getConstantValueForEnumMemberInitializer ( initializer : Expression ) : number {
7441
7443
return evalConstant ( initializer ) ;
7442
7444
7443
7445
function evalConstant ( e : Node ) : number {
7444
7446
switch ( e . kind ) {
7445
7447
case SyntaxKind . PrefixOperator :
7446
7448
var value = evalConstant ( ( < UnaryExpression > e ) . operand ) ;
7447
- if ( value === undefined ) return undefined ;
7449
+ if ( value === undefined ) {
7450
+ return undefined ;
7451
+ }
7448
7452
switch ( ( < UnaryExpression > e ) . operator ) {
7449
7453
case SyntaxKind . PlusToken : return value ;
7450
7454
case SyntaxKind . MinusToken : return - value ;
7451
- case SyntaxKind . TildeToken : return ~ value ;
7455
+ case SyntaxKind . TildeToken : return compilerOptions . propagateEnumConstants ? ~ value : undefined ;
7452
7456
}
7453
7457
return undefined ;
7454
7458
case SyntaxKind . BinaryExpression :
7455
- if ( ! program . getCompilerOptions ( ) . propagateEnumConstants ) return undefined ;
7459
+ if ( ! compilerOptions . propagateEnumConstants ) {
7460
+ return undefined ;
7461
+ }
7456
7462
7457
7463
var left = evalConstant ( ( < BinaryExpression > e ) . left ) ;
7458
- if ( left === undefined ) return undefined ;
7464
+ if ( left === undefined ) {
7465
+ return undefined ;
7466
+ }
7459
7467
var right = evalConstant ( ( < BinaryExpression > e ) . right ) ;
7460
- if ( right === undefined ) return undefined ;
7468
+ if ( right === undefined ) {
7469
+ return undefined ;
7470
+ }
7461
7471
switch ( ( < BinaryExpression > e ) . operator ) {
7462
7472
case SyntaxKind . BarToken : return left | right ;
7463
7473
case SyntaxKind . AmpersandToken : return left & right ;
7464
7474
case SyntaxKind . PlusToken : return left + right ;
7465
7475
case SyntaxKind . MinusToken : return left - right ;
7466
7476
case SyntaxKind . GreaterThanGreaterThanToken : return left >> right ;
7477
+ case SyntaxKind . GreaterThanGreaterThanGreaterThanToken : return left >>> right ;
7467
7478
case SyntaxKind . LessThanLessThanToken : return left << right ;
7468
7479
}
7469
7480
return undefined ;
7470
7481
case SyntaxKind . NumericLiteral :
7471
7482
return + ( < LiteralExpression > e ) . text ;
7472
7483
case SyntaxKind . Identifier :
7484
+ case SyntaxKind . IndexedAccess :
7473
7485
case SyntaxKind . PropertyAccess :
7474
- if ( ! program . getCompilerOptions ( ) . propagateEnumConstants ) return undefined ;
7486
+ if ( ! compilerOptions . propagateEnumConstants ) {
7487
+ return undefined ;
7488
+ }
7475
7489
7476
- var enumSymbol : Symbol ;
7490
+ var member = initializer . parent ;
7491
+ var currentType = getTypeOfSymbol ( getSymbolOfNode ( member . parent ) ) ;
7492
+ var enumType : Type ;
7477
7493
var propertyName : string ;
7478
7494
7479
7495
if ( e . kind === SyntaxKind . Identifier ) {
7480
7496
// unqualified names can refer to member that reside in different declaration of the enum so just doing name resolution won't work.
7481
7497
// instead pick symbol that correspond of enum declaration and later try to fetch member from the symbol
7482
- enumSymbol = getSymbolOfNode ( member . parent ) ;
7498
+ enumType = currentType ;
7483
7499
propertyName = ( < Identifier > e ) . text ;
7484
7500
}
7501
+ else if ( e . kind === SyntaxKind . IndexedAccess ) {
7502
+ if ( ( < IndexedAccess > e ) . index . kind !== SyntaxKind . StringLiteral ) {
7503
+ return undefined ;
7504
+ }
7505
+ var enumType = getTypeOfNode ( ( < IndexedAccess > e ) . object ) ;
7506
+ if ( enumType !== currentType ) {
7507
+ return undefined ;
7508
+ }
7509
+ propertyName = ( < LiteralExpression > ( < IndexedAccess > e ) . index ) . text ;
7510
+ }
7485
7511
else {
7486
7512
// left part in PropertyAccess should be resolved to the symbol of enum that declared 'member'
7487
- enumSymbol = resolveEntityName ( member , ( < PropertyAccess > e ) . left , SymbolFlags . Enum , /*suppressErrors*/ true ) ;
7488
-
7489
- if ( enumSymbol !== getSymbolOfNode ( member . parent ) ) return undefined ;
7490
- propertyName = ( < Identifier > ( < PropertyAccess > e ) . right ) . text ;
7513
+ var enumType = getTypeOfNode ( ( < PropertyAccess > e ) . left ) ;
7514
+ if ( enumType !== currentType ) {
7515
+ return undefined ;
7516
+ }
7517
+ propertyName = ( < PropertyAccess > e ) . right . text ;
7491
7518
}
7492
7519
7493
- var propertySymbol = enumSymbol . exports [ propertyName ] ;
7494
- if ( ! propertyName || ! ( propertySymbol . flags & SymbolFlags . EnumMember ) ) return undefined ;
7495
- var propertyDecl = < EnumMember > propertySymbol . valueDeclaration ;
7520
+ if ( propertyName === undefined ) {
7521
+ return undefined ;
7522
+ }
7523
+ var property = getPropertyOfObjectType ( enumType , propertyName ) ;
7524
+ if ( ! ( property . flags & SymbolFlags . EnumMember ) ) {
7525
+ return undefined ;
7526
+ }
7527
+ var propertyDecl = < EnumMember > property . valueDeclaration ;
7496
7528
// self references are illegal
7497
- if ( member === propertyDecl ) return undefined ;
7498
- // enumMemberValue might be undefined if corresponding enum value was not yet computed
7499
- // and it is ok to return undefined in this case (use before defition)
7529
+ if ( member === propertyDecl ) {
7530
+ return undefined ;
7531
+ }
7532
+
7533
+ // illegal case: forward reference
7534
+ if ( ! isDefinedBefore ( propertyDecl , member ) ) {
7535
+ return undefined ;
7536
+ }
7500
7537
return < number > getNodeLinks ( propertyDecl ) . enumMemberValue ;
7501
7538
}
7502
7539
}
0 commit comments