-
Notifications
You must be signed in to change notification settings - Fork 12.5k
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
Enable JS emit for noCheck and noCheck for transpileModule #58364
Conversation
@typescript-bot perf test this faster |
@weswigham Here they are:
tscComparison Report - baseline..pr
System info unknown
Hosts
Scenarios
Developer Information: |
|
||
!!!! File file1.js missing from original emit, but present in noCheck emit | ||
//// [file1.js] | ||
export const x = 3; |
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.
No checker error, so the emit happens. 🤷♂️
} | ||
declare var k: c | m.c; | ||
-declare var l: c | m.c; | ||
+declare var l: m.c | c; |
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.
Union order swaps - the EmitResolver
during js+.d.ts emit happens to create these types in the reverse order of a full typecheck.
!!! related TS2304 multiLinePropertyAccessAndArrowFunctionIndent1.ts:1:18: Cannot find name 'role'. | ||
!!! related TS2304 multiLinePropertyAccessAndArrowFunctionIndent1.ts:2:18: Cannot find name 'Role'. | ||
!!! related TS2503 multiLinePropertyAccessAndArrowFunctionIndent1.ts:4:26: Cannot find namespace 'ng'. | ||
!!! related TS2304 multiLinePropertyAccessAndArrowFunctionIndent1.ts:4:53: Cannot find name 'Role'. |
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 top-level return
is a grammar error that normally blocks us reporting all these errors. Calculating emit flags for them lazily, however, manifests these errors. Do note: this is also technically a correctness improvement - previously, block scoped bindings and the like inside a top-level return
like this wouldn't get transformed according to the target
because we'd assume we'd calculated their NodeCheckFlags
when in fact we hadn't. Still, these errors are basically silent, even if they're reasonable, hence the warning in the error log. I could probably silence these and get the old behavior back if I really tried, I'm just not sure it's necessary.
|
||
!!!! File all.d.ts missing from original emit, but present in noCheck emit | ||
//// [all.d.ts] | ||
declare module "ref/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.
Now that this isn't emitDeclarationOnly
, this configuration of compiler options is forbidden, thus produces no output again. (Even with noCheck
)
@@ -846,7 +846,7 @@ type AnyArr = [...any]; | |||
declare const tc4: [...string[], number, number, number]; | |||
declare function concat2<T extends readonly unknown[], U extends readonly unknown[]>(t: T, u: U): (T[number] | U[number])[]; | |||
-declare const tc5: (2 | 4 | 1 | 3 | 6 | 5)[]; | |||
+declare const tc5: (1 | 2 | 3 | 6 | 4 | 5)[]; | |||
+declare const tc5: (3 | 2 | 1 | 6 | 4 | 5)[]; |
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 union order shifts again. Presumably the EmitResolver
usages in js emit tweak the order we manifest these number types in.
|
||
!!!! File autoAccessor1.js missing from original emit, but present in noCheck emit | ||
//// [autoAccessor1.js] | ||
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { |
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 target
error for auto-accessors, Properties with the 'accessor' modifier are only available when targeting ECMAScript 2015 and higher.
is a checker error. So when it's suppressed, we happily do emit.
699039b
to
6e919ad
Compare
8ecd6bf
to
f3eab73
Compare
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
-exports.a = void 0; | ||
-exports.a = x.c; |
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 think this is a case where the noCheck
output is an improvement. As a perf optimization, I made reference marking with an Unspecified
hint skip all Ambient
nodes - that causes this change. The export declare import
statement in this file usually gets transformed into the output js, even though it has a declare
modifier. That's likely because the declare
modifier on an import is an error, so the alias marking is done unconditionally. In any case, since the input has a syntax/grammar type error, I think it's fine for the output to diverge a bit like this. I could bring it in-line (either by changing normal behavior to elide this, or noCheck
to retain it), but I'm not sure it's worth the effort, given the error.
@typescript-bot perf test this faster I still need to sprinkle around setting the |
@weswigham Here they are:
tscComparison Report - baseline..pr
System info unknown
Hosts
Scenarios
Developer Information: |
Much better, no more check regressions, only emit ones, and those aughta get fixed with proper application of |
@typescript-bot perf test this faster |
@weswigham Here they are:
tscComparison Report - baseline..pr
System info unknown
Hosts
Scenarios
Developer Information: |
@typescript-bot perf test this faster |
@weswigham Here they are:
tscComparison Report - baseline..pr
System info unknown
Hosts
Scenarios
Developer Information: |
@@ -5761,10 +5777,11 @@ export interface EmitResolver { | |||
isValueAliasDeclaration(node: Node): boolean; | |||
isReferencedAliasDeclaration(node: Node, checkChildren?: boolean): boolean; | |||
isTopLevelValueImportEqualsWithEntityName(node: ImportEqualsDeclaration): boolean; | |||
getNodeCheckFlags(node: Node): NodeCheckFlags; | |||
hasNodeCheckFlag(node: Node, flags: LazyNodeCheckFlags): boolean; |
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.
All in all, I wonder how many other flag checks could be done like this (I did something similar for another flag which helped perf too)
For fun @typescript-bot perf test this predictable |
@jakebailey Here they are:
tscComparison Report - baseline..pr
System info unknown
Hosts
Scenarios
tsserverComparison Report - baseline..pr
System info unknown
Hosts
Scenarios
startupComparison Report - baseline..pr
System info unknown
Hosts
Scenarios
Developer Information: |
@typescript-bot perf test this predictable |
@jakebailey Here they are:
tscComparison Report - baseline..pr
System info unknown
Hosts
Scenarios
tsserverComparison Report - baseline..pr
System info unknown
Hosts
Scenarios
startupComparison Report - baseline..pr
System info unknown
Hosts
Scenarios
Developer Information: |
The perf results are still seemingly showing a regression in emit time on various projects. Not sure what's going on there but I'll try and profile... |
I mentioned it in our meeting, but the only things not |
…it to be done without type checking
@@ -924,6 +930,14 @@ export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFi | |||
forEachChild(node, collectLinkedAliases); | |||
} | |||
|
|||
function markLinkedReferences(file: SourceFile) { | |||
ts.forEachChildRecursively(file, n => { |
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.
can this instead check if file doesnt have TypeChecked
flag and do this work and then we can get rid of getDiagnostics
all together from getEmitResolver()
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 quite - the TypeChecked
flag is, ironically, set on files whose type checking is skipped. Maybe it's a misnomer, but it really just means "Has checkSourceFile
been called on this node?". I get your drift though and, yeah, we could probably do a bit of refactoring to use a node flag to track the diagnostic walk state of the containing file. I'll probably put that up as a separate cleanup, though. I also think I want to move around/refactor the API logic for collectLinkedAliases
so the API is harder to misuse, and will probably change markLinkedReferences
to match, so I'll put all those nonfunctional changes in a separate PR (which should have a 0-test diff).
I'm having a pretty hard time figuring out where the slowdown is; the vscode benchmark takes a long time so two runs are just not comparable, even in predictable mode on a perf locked core. @typescript-bot perf test this faster |
@jakebailey Here they are:
tscComparison Report - baseline..pr
System info unknown
Hosts
Scenarios
Developer Information: |
return !!(getNodeCheckFlags(node) & flag); | ||
} | ||
|
||
function calculateNodeCheckFlagWorker(node: Node, flag: LazyNodeCheckFlags) { |
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.
Is there a chance for this to go out of sync with other code that sets these flags?
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.
100% absolutely, but since we run with noCheck
and compare the result to a normal emit for every test we have, it's very likely a test will catch it.
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 also do reuse the actual flag-setting functions, just not the traversal to reach and invoke them. So the "should this flag be set" logic should be synced, at least.
@typescript-bot pack this |
Hey @DanielRosenwasser, I've packed this into an installable tgz. You can install it for testing by referencing it in your
and then running There is also a playground for this build and an npm module you can use via |
I thought I'd try this out on a ts-loader project, so tested out pyright's build before and after. Somehow, it's slower? I suppose this doesn't actually use transpileModule since they're using const enums and everything :( $ hyperfine 'node --max_old_space_size=8192 ./node_modules/webpack-cli/bin/cli.js --mode development'
Benchmark 1: node --max_old_space_size=8192 ./node_modules/webpack-cli/bin/cli.js --mode development
Time (mean ± σ): 14.899 s ± 0.221 s [User: 22.878 s, System: 1.591 s]
Range (min … max): 14.379 s … 15.200 s 10 runs
$ hyperfine 'node --max_old_space_size=8192 ./node_modules/webpack-cli/bin/cli.js --mode development'
Benchmark 1: node --max_old_space_size=8192 ./node_modules/webpack-cli/bin/cli.js --mode development
Time (mean ± σ): 15.110 s ± 0.164 s [User: 23.219 s, System: 1.541 s]
Range (min … max): 14.888 s … 15.395 s 10 runs |
Ya, |
In lieu of real-world benchmarks, I used ts.transpileModule(input, {
fileName,
compilerOptions: { target: ts.ScriptTarget.ESNext, module: ts.ModuleKind.Preserve } },
);
So, for files of a non-trivial size, it sure seems like a good 2x speed boost for I have not been able to pin down the perf regression, if there even is one. But I'm pretty sure we should just take this anyhow. |
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.
Looks good to me, though I'm not 100% thrilled with the increase in test time; it looks like it increases CI time from something like 7 minutes to 8.
* upstream/main: (37 commits) Added NoTruncation flag to completions (microsoft#58719) Clone node to remove location even when it has been modified if needed (microsoft#58706) Properly account for `this` argument in intersection apparent type caching (microsoft#58677) Fix: Include Values of Script Extensions for Unicode Property Value Expressions in Regular Expressions (microsoft#58615) In `reScanSlashToken` use `charCodeChecked` not `codePointChecked` (microsoft#58727) Shorten error spans for errors reported on constructor declarations (microsoft#58061) Mark file as skips typechecking if it contains ts-nocheck (microsoft#58593) Fixed an issue with broken `await using` declarations in `for of` loops (microsoft#56466) Do not expand type references in keyof and index access (microsoft#58715) Improve the performance of isolatedDeclarations quickfix (microsoft#58722) Unwrap `NoInfer` types when narrowing (microsoft#58292) Recover from type reuse errors by falling back to inferred type printing (microsoft#58720) Fixing self import (microsoft#58718) Enable JS emit for noCheck and noCheck for transpileModule (microsoft#58364) Revert PR 55371 (microsoft#58702) Update dependencies (microsoft#58639) Fix baselines after PR 58621 (microsoft#58705) Do not infer `yield*` type from contextual `TReturn` (microsoft#58621) `await using` normative changes (microsoft#58624) Handling statements from a known source file (microsoft#58679) ...
This PR enables
noCheck
for JS emit, and tests all js emit tests withnoCheck
, just as we do declaration emit tests withnoCheck
. It also enablesnoCheck
fortranspileModule
by default.