- 
          
- 
                Notifications
    You must be signed in to change notification settings 
- Fork 676
feat: support element access of enum #2950
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|  | @@ -1522,6 +1522,49 @@ export class Compiler extends DiagnosticEmitter { | |||||||||||||
| return true; | ||||||||||||||
| } | ||||||||||||||
|  | ||||||||||||||
| private ensureEnumToString(enumElement: Enum, reportNode: Node): string | null { | ||||||||||||||
| if (enumElement.toStringFunctionName) return enumElement.toStringFunctionName; | ||||||||||||||
|  | ||||||||||||||
| if (!this.compileEnum(enumElement)) return null; | ||||||||||||||
| if (enumElement.is(CommonFlags.Const)) { | ||||||||||||||
| this.errorRelated( | ||||||||||||||
| DiagnosticCode.A_const_enum_member_can_only_be_accessed_using_a_string_literal, | ||||||||||||||
| reportNode.range, enumElement.identifierNode.range | ||||||||||||||
| ); | ||||||||||||||
| return null; | ||||||||||||||
| } | ||||||||||||||
|  | ||||||||||||||
| let members = enumElement.members; | ||||||||||||||
| if (!members) return null; | ||||||||||||||
|  | ||||||||||||||
| let module = this.module; | ||||||||||||||
| const isInline = enumElement.hasDecorator(DecoratorFlags.Inline); | ||||||||||||||
|  | ||||||||||||||
| const functionName = `${enumElement.internalName}#${CommonNames.EnumToString}`; | ||||||||||||||
| enumElement.toStringFunctionName = functionName; | ||||||||||||||
|  | ||||||||||||||
| let exprs = new Array<ExpressionRef>(); | ||||||||||||||
| // when the values are the same, TS returns the last enum value name that appears | ||||||||||||||
| for (let _keys = Map_keys(members), _values = Map_values(members), i = 1, k = _keys.length; i <= k; ++i) { | ||||||||||||||
| let enumValueName = unchecked(_keys[k - i]); | ||||||||||||||
| let member = unchecked(_values[k - i]); | ||||||||||||||
| 
      Comment on lines
    
      +1548
     to 
      +1550
    
   There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 
        Suggested change
       
 Doesn't this work? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if  | ||||||||||||||
| if (member.kind != ElementKind.EnumValue) continue; | ||||||||||||||
| let enumValue = <EnumValue>member; | ||||||||||||||
| const enumValueExpr = isInline | ||||||||||||||
| ? module.i32(i64_low(enumValue.constantIntegerValue)) | ||||||||||||||
| : module.global_get(enumValue.internalName, TypeRef.I32); | ||||||||||||||
| let expr = module.if( | ||||||||||||||
| module.binary(BinaryOp.EqI32, enumValueExpr, module.local_get(0, TypeRef.I32)), | ||||||||||||||
| module.return(this.ensureStaticString(enumValueName)) | ||||||||||||||
| ); | ||||||||||||||
| exprs.push(expr); | ||||||||||||||
| } | ||||||||||||||
| exprs.push(module.unreachable()); | ||||||||||||||
| module.addFunction(functionName, TypeRef.I32, TypeRef.I32, null, module.block(null, exprs, TypeRef.I32)); | ||||||||||||||
|  | ||||||||||||||
| return functionName; | ||||||||||||||
| } | ||||||||||||||
|  | ||||||||||||||
| // === Functions ================================================================================ | ||||||||||||||
|  | ||||||||||||||
| /** Compiles a priorly resolved function. */ | ||||||||||||||
|  | @@ -7092,7 +7135,17 @@ export class Compiler extends DiagnosticEmitter { | |||||||||||||
| ): ExpressionRef { | ||||||||||||||
| let module = this.module; | ||||||||||||||
| let targetExpression = expression.expression; | ||||||||||||||
| let targetType = this.resolver.resolveExpression(targetExpression, this.currentFlow); // reports | ||||||||||||||
| let resolver = this.resolver; | ||||||||||||||
| let targetElement = resolver.lookupExpression(targetExpression, this.currentFlow, Type.auto, ReportMode.Swallow); | ||||||||||||||
| if (targetElement && targetElement.kind == ElementKind.Enum) { | ||||||||||||||
| const elementExpr = this.compileExpression(expression.elementExpression, Type.i32, Constraints.ConvImplicit); | ||||||||||||||
| There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It looks like we're allowing  (It also seems like we don't have a good error for  There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, since the current runtime only support to get enum value from compilation time known string (aka string literal).  | ||||||||||||||
| const toStringFunctionName = this.ensureEnumToString(<Enum>targetElement, expression); | ||||||||||||||
| this.currentType = this.program.stringInstance.type; | ||||||||||||||
| if (toStringFunctionName == null) return module.unreachable(); | ||||||||||||||
| return module.call(toStringFunctionName, [ elementExpr ], TypeRef.I32); | ||||||||||||||
| } | ||||||||||||||
|  | ||||||||||||||
| let targetType = resolver.resolveExpression(targetExpression, this.currentFlow); | ||||||||||||||
| if (targetType) { | ||||||||||||||
| let classReference = targetType.getClassOrWrapper(this.program); | ||||||||||||||
| if (classReference) { | ||||||||||||||
|  | ||||||||||||||
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| { | ||
| "asc_flags": [], | ||
| "stderr": [ | ||
| "TS2476: A const enum member can only be accessed using a string literal.", | ||
| "EOF" | ||
| ] | ||
| } | 
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| const enum CE { | ||
| CE0, | ||
| CE1, | ||
| CE2, | ||
| } | ||
|  | ||
| assert(CE[CE.CE0] === "CE0"); | ||
|  | ||
| ERROR("EOF"); | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you add a couple blank lines in here? It's a little hard to read