@@ -1522,56 +1522,41 @@ export class Compiler extends DiagnosticEmitter {
15221522 return true ;
15231523 }
15241524
1525- private ensureEnumToString ( enumElement : Enum ) : string | null {
1525+ private ensureEnumToString ( enumElement : Enum , reportNode : Node ) : string | null {
15261526 if ( ! this . compileEnum ( enumElement ) ) return null ;
1527+ if ( enumElement . is ( CommonFlags . Const ) ) {
1528+ this . errorRelated (
1529+ DiagnosticCode . A_const_enum_member_can_only_be_accessed_using_a_string_literal ,
1530+ reportNode . range , enumElement . identifierNode . range
1531+ ) ;
1532+ return null ;
1533+ }
15271534 let members = enumElement . members ;
15281535 if ( ! members ) return null ; // TODO
1529-
1530- let module = this . module ;
1536+ if ( enumElement . toStringFunctionName ) return enumElement . toStringFunctionName ;
15311537 const functionName = `${ enumElement . internalName } #${ CommonNames . EnumToString } ` ;
1532- const isInline = enumElement . is ( CommonFlags . Const ) || enumElement . hasDecorator ( DecoratorFlags . Inline ) ;
1533- let _keys = Map_keys ( members ) , _values = Map_values ( members ) ;
1534- if ( isInline ) {
1535- let valueToNames : Map < i32 , string > = new Map ( ) ;
1536- for ( let i = 0 , k = _keys . length ; i < k ; ++ i ) {
1537- let name = unchecked ( _keys [ i ] ) ;
1538- let member = unchecked ( _values [ i ] ) ;
1539- if ( member . kind != ElementKind . EnumValue ) continue ;
1540- let enumValue = < EnumValue > member ;
1541- valueToNames . set ( i64_low ( enumValue . constantIntegerValue ) , name ) ;
1542- }
1543- let exprs = new Array < ExpressionRef > ( ) ;
1544- for ( let [ value , names ] of valueToNames ) {
1545- let expr = module . if (
1546- module . binary ( BinaryOp . EqI32 , module . i32 ( value ) , module . local_get ( 0 , TypeRef . I32 ) ) ,
1547- module . return ( this . ensureStaticString ( names ) )
1548- ) ;
1549- exprs . push ( expr ) ;
1550- }
1551- exprs . push ( module . unreachable ( ) ) ;
1552- module . addFunction ( functionName , TypeRef . I32 , TypeRef . I32 , null , module . block ( null , exprs , TypeRef . I32 ) ) ;
1553- return functionName ;
1554- } else {
1555- let internalNameToNames : Map < string , string > = new Map ( ) ;
1556- for ( let i = 0 , k = _keys . length ; i < k ; ++ i ) {
1557- let name = unchecked ( _keys [ i ] ) ;
1558- let member = unchecked ( _values [ i ] ) ;
1559- if ( member . kind != ElementKind . EnumValue ) continue ;
1560- let enumValue = < EnumValue > member ;
1561- internalNameToNames . set ( enumValue . internalName , name ) ;
1562- }
1563- let exprs = new Array < ExpressionRef > ( ) ;
1564- for ( let [ internalName , names ] of internalNameToNames ) {
1565- let expr = module . if (
1566- module . binary ( BinaryOp . EqI32 , module . global_get ( internalName , TypeRef . I32 ) , module . local_get ( 0 , TypeRef . I32 ) ) ,
1567- module . return ( this . ensureStaticString ( names ) )
1568- ) ;
1569- exprs . push ( expr ) ;
1570- }
1571- exprs . push ( module . unreachable ( ) ) ;
1572- module . addFunction ( functionName , TypeRef . I32 , TypeRef . I32 , null , module . block ( null , exprs , TypeRef . I32 ) ) ;
1573- return functionName ;
1538+ enumElement . toStringFunctionName = functionName ;
1539+ const isInline = enumElement . hasDecorator ( DecoratorFlags . Inline ) ;
1540+ let module = this . module ;
1541+ let exprs = new Array < ExpressionRef > ( ) ;
1542+ // when the values are the same, TS returns the last enum value name that appears
1543+ for ( let _keys = Map_keys ( members ) , _values = Map_values ( members ) , i = 1 , k = _keys . length ; i <= k ; ++ i ) {
1544+ let enumValueName = unchecked ( _keys [ k - i ] ) ;
1545+ let member = unchecked ( _values [ k - i ] ) ;
1546+ if ( member . kind != ElementKind . EnumValue ) continue ;
1547+ let enumValue = < EnumValue > member ;
1548+ const enumValueExpr = isInline
1549+ ? module . i32 ( i64_low ( enumValue . constantIntegerValue ) )
1550+ : module . global_get ( enumValue . internalName , TypeRef . I32 ) ;
1551+ let expr = module . if (
1552+ module . binary ( BinaryOp . EqI32 , enumValueExpr , module . local_get ( 0 , TypeRef . I32 ) ) ,
1553+ module . return ( this . ensureStaticString ( enumValueName ) )
1554+ ) ;
1555+ exprs . push ( expr ) ;
15741556 }
1557+ exprs . push ( module . unreachable ( ) ) ;
1558+ module . addFunction ( functionName , TypeRef . I32 , TypeRef . I32 , null , module . block ( null , exprs , TypeRef . I32 ) ) ;
1559+ return functionName ;
15751560 }
15761561
15771562 // === Functions ================================================================================
@@ -7147,9 +7132,10 @@ export class Compiler extends DiagnosticEmitter {
71477132 let resolver = this . resolver ;
71487133 let targetElement = resolver . lookupExpression ( targetExpression , this . currentFlow , Type . auto , ReportMode . Swallow ) ;
71497134 if ( targetElement && targetElement . kind == ElementKind . Enum ) {
7150- const toStringFunctionName = this . ensureEnumToString ( < Enum > targetElement ) ;
7151- if ( toStringFunctionName == null ) return module . unreachable ( ) ;
71527135 const elementExpr = this . compileExpression ( expression . elementExpression , Type . i32 , Constraints . ConvImplicit ) ;
7136+ const toStringFunctionName = this . ensureEnumToString ( < Enum > targetElement , expression ) ;
7137+ this . currentType = this . program . stringInstance . type ;
7138+ if ( toStringFunctionName == null ) return module . unreachable ( ) ;
71537139 return module . call ( toStringFunctionName , [ elementExpr ] , TypeRef . I32 ) ;
71547140 }
71557141
0 commit comments