@@ -306,6 +306,22 @@ module ts {
306306 // return undefined if we can't find a symbol.
307307 }
308308
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+
309325 function resolveName ( location : Node , name : string , meaning : SymbolFlags , nameNotFoundMessage : DiagnosticMessage , nameArg : string ) : Symbol {
310326 var errorLocation = location ;
311327 var result : Symbol ;
@@ -330,18 +346,8 @@ module ts {
330346 // Block-scoped variables can not be used before their definition
331347 var declaration = forEach ( s . declarations , d => d . flags & NodeFlags . BlockScoped ? d : undefined ) ;
332348 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 ) ) ;
345351 }
346352 }
347353 return s ;
@@ -489,12 +495,10 @@ module ts {
489495 }
490496
491497 // 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 {
493499 if ( name . kind === SyntaxKind . Identifier ) {
494500 // 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 ) ) ;
498502 if ( ! symbol ) {
499503 return ;
500504 }
@@ -504,10 +508,8 @@ module ts {
504508 if ( ! namespace || namespace === unknownSymbol || ( < QualifiedName > name ) . right . kind === SyntaxKind . Missing ) return ;
505509 var symbol = getSymbol ( namespace . exports , ( < QualifiedName > name ) . right . text , meaning ) ;
506510 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 ) ) ;
511513 return ;
512514 }
513515 }
@@ -7410,13 +7412,13 @@ module ts {
74107412 var autoValue = 0 ;
74117413 var ambient = isInAmbientContext ( node ) ;
74127414
7413- forEach ( node . members , member => {
7415+ forEach ( node . members , member => {
74147416 if ( isNumericName ( member . name . text ) ) {
74157417 error ( member . name , Diagnostics . An_enum_member_cannot_have_a_numeric_name ) ;
74167418 }
74177419 var initializer = member . initializer ;
74187420 if ( initializer ) {
7419- autoValue = getConstantValueForEnumMemberInitializer ( member , initializer ) ;
7421+ autoValue = getConstantValueForEnumMemberInitializer ( initializer ) ;
74207422 if ( autoValue === undefined && ! ambient ) {
74217423 // Only here do we need to check that the initializer is assignable to the enum type.
74227424 // If it is a constant value (not undefined), it is syntactically constrained to be a number.
@@ -7437,66 +7439,101 @@ module ts {
74377439 nodeLinks . flags |= NodeCheckFlags . EnumValuesComputed ;
74387440 }
74397441
7440- function getConstantValueForEnumMemberInitializer ( member : EnumMember , initializer : Expression ) : number {
7442+ function getConstantValueForEnumMemberInitializer ( initializer : Expression ) : number {
74417443 return evalConstant ( initializer ) ;
74427444
74437445 function evalConstant ( e : Node ) : number {
74447446 switch ( e . kind ) {
74457447 case SyntaxKind . PrefixOperator :
74467448 var value = evalConstant ( ( < UnaryExpression > e ) . operand ) ;
7447- if ( value === undefined ) return undefined ;
7449+ if ( value === undefined ) {
7450+ return undefined ;
7451+ }
74487452 switch ( ( < UnaryExpression > e ) . operator ) {
74497453 case SyntaxKind . PlusToken : return value ;
74507454 case SyntaxKind . MinusToken : return - value ;
7451- case SyntaxKind . TildeToken : return ~ value ;
7455+ case SyntaxKind . TildeToken : return compilerOptions . propagateEnumConstants ? ~ value : undefined ;
74527456 }
74537457 return undefined ;
74547458 case SyntaxKind . BinaryExpression :
7455- if ( ! program . getCompilerOptions ( ) . propagateEnumConstants ) return undefined ;
7459+ if ( ! compilerOptions . propagateEnumConstants ) {
7460+ return undefined ;
7461+ }
74567462
74577463 var left = evalConstant ( ( < BinaryExpression > e ) . left ) ;
7458- if ( left === undefined ) return undefined ;
7464+ if ( left === undefined ) {
7465+ return undefined ;
7466+ }
74597467 var right = evalConstant ( ( < BinaryExpression > e ) . right ) ;
7460- if ( right === undefined ) return undefined ;
7468+ if ( right === undefined ) {
7469+ return undefined ;
7470+ }
74617471 switch ( ( < BinaryExpression > e ) . operator ) {
74627472 case SyntaxKind . BarToken : return left | right ;
74637473 case SyntaxKind . AmpersandToken : return left & right ;
74647474 case SyntaxKind . PlusToken : return left + right ;
74657475 case SyntaxKind . MinusToken : return left - right ;
74667476 case SyntaxKind . GreaterThanGreaterThanToken : return left >> right ;
7477+ case SyntaxKind . GreaterThanGreaterThanGreaterThanToken : return left >>> right ;
74677478 case SyntaxKind . LessThanLessThanToken : return left << right ;
74687479 }
74697480 return undefined ;
74707481 case SyntaxKind . NumericLiteral :
74717482 return + ( < LiteralExpression > e ) . text ;
74727483 case SyntaxKind . Identifier :
7484+ case SyntaxKind . IndexedAccess :
74737485 case SyntaxKind . PropertyAccess :
7474- if ( ! program . getCompilerOptions ( ) . propagateEnumConstants ) return undefined ;
7486+ if ( ! compilerOptions . propagateEnumConstants ) {
7487+ return undefined ;
7488+ }
74757489
7476- var enumSymbol : Symbol ;
7490+ var member = initializer . parent ;
7491+ var currentType = getTypeOfSymbol ( getSymbolOfNode ( member . parent ) ) ;
7492+ var enumType : Type ;
74777493 var propertyName : string ;
74787494
74797495 if ( e . kind === SyntaxKind . Identifier ) {
74807496 // unqualified names can refer to member that reside in different declaration of the enum so just doing name resolution won't work.
74817497 // 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 ;
74837499 propertyName = ( < Identifier > e ) . text ;
74847500 }
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+ }
74857511 else {
74867512 // 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 ;
74917518 }
74927519
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 ;
74967528 // 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+ }
75007537 return < number > getNodeLinks ( propertyDecl ) . enumMemberValue ;
75017538 }
75027539 }
0 commit comments