-
Notifications
You must be signed in to change notification settings - Fork 694
Const enum inlining and synthetic comment emit support #1599
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
Conversation
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.
Pull Request Overview
This PR implements const enum inlining and synthetic comment emit support for the TypeScript Go port. The implementation enables the replacement of const enum property accesses with their literal values, along with optional synthetic comments to preserve the original const enum reference for debugging purposes.
Key changes include:
- Adds const enum inlining transformer that replaces const enum accesses with literal values
- Implements synthetic comment support in the printer for preserving original enum references
- Extends the emit resolver interface to support constant value resolution
Reviewed Changes
Copilot reviewed 101 out of 101 changed files in this pull request and generated 2 comments.
Show a summary per file
File | Description |
---|---|
internal/transformers/inliners/constenum.go | New const enum inlining transformer that replaces enum property accesses with their literal values |
internal/printer/printer.go | Enhanced printer with synthetic comment support and refactored comment handling |
internal/printer/emitresolver.go | Extended emit resolver interface to include GetConstantValue method |
internal/printer/emitcontext.go | Added synthetic comment structures and management methods |
internal/compiler/emitter.go | Integrated const enum inlining transformer into compilation pipeline |
internal/checker/emitresolver.go | Implemented GetConstantValue method in emit resolver |
internal/checker/checker.go | Fixed symbol resolution for const enum inlining support |
testdata/baselines/reference/* | Updated test baselines showing const enum inlining behavior |
Does this fix #1216? |
@@ -15087,7 +15087,7 @@ func (c *Checker) resolveEntityName(name *ast.Node, meaning ast.SymbolFlags, ign | |||
name.Parent != nil && name.Parent.Kind == ast.KindJSExportAssignment) { | |||
c.markSymbolOfAliasDeclarationIfTypeOnly(getAliasDeclarationFromName(name), symbol, nil /*finalTarget*/, true /*overwriteEmpty*/, nil, "") | |||
} | |||
if symbol.Flags&meaning == 0 && !dontResolveAlias { | |||
if symbol.Flags&meaning == 0 && !dontResolveAlias && symbol.Flags&ast.SymbolFlagsAlias != 0 { |
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.
In strada, checkExpressionCached
on a.b.c.d
caches resolved symbols on a.b.c
and a.b
and a
. getConstantValue
uses these cached symbols to shortcut its' logic. In corsa, it does not, and, in so doing, reveals that here we try to call resolveAlias
on non-alias (module) symbols when we consider if we want to inline module.exports
. This fixes that.
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.
Are there more inliners than just constenum?
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.
As of right now, no, but we've toyed with adding minifer-like emit passes in the past, so it's a logical place to group them.
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.
I don't think that's going to happen, but 😄
return tx.NewTransformer(tx.visit, emitContext) | ||
} | ||
|
||
func (tx *ConstEnumInliningTransformer) visit(node *ast.Node) *ast.Node { |
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.
Wow, I love how short this is
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.
Yeah, I inlined some indirections from strada.
...ference/submodule/compiler/blockScopedEnumVariablesUseBeforeDef_verbatimModuleSyntax.js.diff
Outdated
Show resolved
Hide resolved
} | ||
const config = { | ||
- a: AfterObject.A, | ||
+ a: 2 /* AfterObject.A */, |
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.
I'm about to push the fix for this one (should be using the calculated options isolatedModules
flag and not the raw one), but this test seems to raise an important issue in VMS, imo - const enum
s really just don't work under it under current rules, do they? Even within the same function...
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.
The emit is bad, but IIRC this emits a checker error here anyway, so it's fair game.
@@ -10,5 +10,5 @@ | |||
-</>; | |||
+const component_1 = require("./component"); | |||
+const React = require("react"); | |||
+let x = (<component_1.MyComp />, <component_1.Prop> a={10} b="hi" />; // error, no type arguments in js | |||
+let x = (<component_1.MyComp />, <Prop> a={10} b="hi" />; // error, no type arguments in js |
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.
This is the only diff that isn't a strict improvement to match strada, imo - seems like swapping from the binder-based import-only resolver to the full emit resolver has changed the behavior of the cjs transform on the Prop
identifier here. Now, this is all syntactic gobbeldeygook because it's a jsx
file with a jsx tag with a type argument, being generously reinterpreted as a comma expression, so the emit here doesn't actually matter, but might indicate a more important bug somewhere in the checker. It'd be trivial to swap the behavior back (without troubleshooting the root cause) by having both the import-only resolver and the checker-resolver on hand and using the import-only one for the cjs transform, though.
@@ -37,9 +37,9 @@ | |||
+ // correct cases: reference to the enum member from different enum declaration | |||
+ Enum1["W1"] = A0; | |||
+ if (typeof Enum1.W1 !== "string") Enum1[Enum1.W1] = "W1"; | |||
+ Enum1["W2"] = Enum1.A0; | |||
+ Enum1["W2"] = 100 /* Enum1.A0 */; |
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.
Not related to your PR, but this is an interesting case, since I assume this is due to us not doing enum merging properly or something
testdata/baselines/reference/submodule/conformance/jsxCheckJsxNoTypeArgumentsAllowed.js.diff
Show resolved
Hide resolved
And yea, this is logically the fix for #1216 since it reenables const enum inlining. I'll edit the OP to close it on merge. |
Looks like my one-liner change to |
This reverts commit a4eb181.
Or not? |
It looks like this panic is unrecovered, so the test suite crashed, leading all tests after it to appear passing.
|
Wait, does Breakpoint fall over if no debugger is attached? Do we need to remove that line? |
Looks like it. I'll just remove the |
Sent #1601 too. |
@@ -917,3 +927,37 @@ func (c *EmitContext) VisitIterationBody(body *ast.Statement, visitor *ast.NodeV | |||
|
|||
return updated | |||
} | |||
|
|||
func (c *EmitContext) SetSyntheticLeadingComments(node *ast.Node, comments []SynthesizedComment) *ast.Node { |
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.
Not this PR, but there are some callers of this I left commented out in the node builder (probably more than that though, just opining)
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.
Sent #1607 before this task slipped out of my brain.
And I just got rid of const enums in our code to switch to tsgo because I thought they are not coming back 😭 |
The synthetic comment support should unblock a handful of TODOs in the node builder for services logic. There might be some helpers missing that are used elsewhere, but all the core printer support is in, since that's most of our const enum emit logic that isn't checker-driven.
Despite appearances, this works differently from how we did const enum inlining in strada - there, we enabled substitutions in the
ts
transform and did const enum inlining late during the substitution pass (a super late pass invoked by the printer just before printing the node), which is also how transforms used to handle renaming exports and a few other things. Like other substitution uses, that's had to change. Now it's a transform executed at the end of the very end of the js transform pipeline instead, so you'll actually see the changed nodes in the AST. Unfortunately, since it's still checker-based, only nodes derived from a checked node get inlined. (So, for example, if a transform manifests anA.B
from nothing into the result tree, andA.B
refers to aconst enum
, the inliner transform doesn't know to inline it since it only inlines nodes related to parsed nodes - in practice, this doesn't seem to be a problem, since transforms don't generally manufacture new references from nothing to const enums - only to globals and helpers and such.)Fixes #1216