Skip to content

Avoid dependent parameters narrowings if any declared symbol of the parameter is assigned to #56313

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

Merged

Conversation

Andarist
Copy link
Contributor

@Andarist Andarist commented Nov 5, 2023

fixes #56312

@typescript-bot typescript-bot added the For Uncommitted Bug PR for untriaged, rejected, closed or missing bug label Nov 5, 2023
@Andarist Andarist changed the title Avoid dependent parameters narrowings if any declared symbols of the parameter are assigned to Avoid dependent parameters narrowings if any declared symbol of the parameter is assigned to Nov 5, 2023
@typescript-bot typescript-bot added For Backlog Bug PRs that fix a backlog bug and removed For Uncommitted Bug PR for untriaged, rejected, closed or missing bug labels Nov 21, 2023
@gabritto
Copy link
Member

gabritto commented Dec 5, 2023

@typescript-bot run DT
@typescript-bot user test this
@typescript-bot test top100
@typescript-bot perf test this

@typescript-bot
Copy link
Collaborator

typescript-bot commented Dec 5, 2023

Heya @gabritto, I've started to run the regular perf test suite on this PR at 6e7aa4d. You can monitor the build here.

Update: The results are in!

@typescript-bot
Copy link
Collaborator

typescript-bot commented Dec 5, 2023

Heya @gabritto, I've started to run the diff-based user code test suite on this PR at 6e7aa4d. You can monitor the build here.

Update: The results are in!

@typescript-bot
Copy link
Collaborator

typescript-bot commented Dec 5, 2023

Heya @gabritto, I've started to run the diff-based top-repos suite on this PR at 6e7aa4d. You can monitor the build here.

Update: The results are in!

@typescript-bot
Copy link
Collaborator

typescript-bot commented Dec 5, 2023

Heya @gabritto, I've started to run the parallelized Definitely Typed test suite on this PR at 6e7aa4d. You can monitor the build here.

Update: The results are in!

@typescript-bot
Copy link
Collaborator

@gabritto Here are the results of running the user test suite comparing main and refs/pull/56313/merge:

There were infrastructure failures potentially unrelated to your change:

  • 2 instances of "Package install failed"

Otherwise...

Something interesting changed - please have a look.

Details

lodash

/mnt/ts_downloads/lodash/tsconfig.json

  • [MISSING] error TS18048: 'string' is possibly 'undefined'.
    • /mnt/ts_downloads/lodash/node_modules/lodash/template.js(199,15)

puppeteer

packages/browsers/test/src/tsconfig.json

@typescript-bot
Copy link
Collaborator

@gabritto
The results of the perf run you requested are in!

Here they are:

Compiler

Comparison Report - baseline..pr
Metric baseline pr Delta Best Worst p-value
Angular - node (v18.15.0, x64)
Memory used 295,371k (± 0.00%) 294,243k (± 0.01%) -1,128k (- 0.38%) 294,228k 294,273k p=0.005 n=6
Parse Time 2.65s (± 0.28%) 2.65s (± 0.40%) ~ 2.63s 2.66s p=0.611 n=6
Bind Time 0.82s (± 0.99%) 0.82s (± 0.00%) ~ 0.82s 0.82s p=0.405 n=6
Check Time 8.12s (± 0.30%) 8.08s (± 0.34%) -0.04s (- 0.51%) 8.05s 8.13s p=0.024 n=6
Emit Time 7.09s (± 0.23%) 7.06s (± 0.31%) -0.03s (- 0.35%) 7.04s 7.10s p=0.035 n=6
Total Time 18.68s (± 0.08%) 18.60s (± 0.18%) -0.08s (- 0.41%) 18.56s 18.64s p=0.005 n=6
Compiler-Unions - node (v18.15.0, x64)
Memory used 192,815k (± 1.23%) 192,783k (± 1.18%) ~ 190,948k 196,675k p=0.471 n=6
Parse Time 1.36s (± 0.62%) 1.37s (± 1.36%) ~ 1.34s 1.39s p=0.277 n=6
Bind Time 0.72s (± 0.00%) 0.72s (± 0.00%) ~ 0.72s 0.72s p=1.000 n=6
Check Time 9.25s (± 0.44%) 9.29s (± 0.36%) ~ 9.25s 9.34s p=0.172 n=6
Emit Time 2.62s (± 0.29%) 2.62s (± 0.56%) ~ 2.60s 2.63s p=1.000 n=6
Total Time 13.95s (± 0.26%) 13.99s (± 0.33%) ~ 13.93s 14.07s p=0.106 n=6
Monaco - node (v18.15.0, x64)
Memory used 347,380k (± 0.01%) 345,811k (± 0.00%) -1,569k (- 0.45%) 345,781k 345,832k p=0.005 n=6
Parse Time 2.46s (± 0.49%) 2.47s (± 0.34%) ~ 2.45s 2.47s p=0.227 n=6
Bind Time 0.93s (± 0.81%) 0.93s (± 0.88%) ~ 0.92s 0.94s p=0.729 n=6
Check Time 6.89s (± 0.60%) 6.88s (± 0.21%) ~ 6.86s 6.90s p=0.419 n=6
Emit Time 4.05s (± 0.51%) 4.06s (± 0.29%) ~ 4.04s 4.07s p=0.192 n=6
Total Time 14.32s (± 0.32%) 14.33s (± 0.12%) ~ 14.31s 14.36s p=1.000 n=6
TFS - node (v18.15.0, x64)
Memory used 302,687k (± 0.01%) 301,492k (± 0.01%) -1,195k (- 0.39%) 301,472k 301,518k p=0.005 n=6
Parse Time 2.00s (± 1.05%) 2.00s (± 0.58%) ~ 1.98s 2.01s p=1.000 n=6
Bind Time 1.00s (± 0.75%) 1.00s (± 1.94%) ~ 0.97s 1.02s p=0.742 n=6
Check Time 6.29s (± 0.19%) 6.29s (± 0.37%) ~ 6.27s 6.33s p=1.000 n=6
Emit Time 3.57s (± 0.53%) 3.58s (± 0.48%) ~ 3.56s 3.60s p=0.516 n=6
Total Time 12.87s (± 0.11%) 12.87s (± 0.14%) ~ 12.85s 12.89s p=0.504 n=6
material-ui - node (v18.15.0, x64)
Memory used 506,740k (± 0.00%) 502,884k (± 0.00%) -3,856k (- 0.76%) 502,862k 502,905k p=0.005 n=6
Parse Time 2.58s (± 0.64%) 2.58s (± 0.21%) ~ 2.57s 2.58s p=0.342 n=6
Bind Time 0.99s (± 1.11%) 0.98s (± 0.84%) -0.01s (- 1.35%) 0.97s 0.99s p=0.045 n=6
Check Time 16.86s (± 0.18%) 16.85s (± 0.48%) ~ 16.70s 16.94s p=0.808 n=6
Emit Time 0.00s (± 0.00%) 0.00s (± 0.00%) ~ 0.00s 0.00s p=1.000 n=6
Total Time 20.43s (± 0.20%) 20.40s (± 0.43%) ~ 20.24s 20.50s p=0.686 n=6
xstate - node (v18.15.0, x64)
Memory used 512,731k (± 0.01%) 509,945k (± 0.02%) -2,786k (- 0.54%) 509,807k 510,097k p=0.005 n=6
Parse Time 3.27s (± 0.45%) 3.27s (± 0.27%) ~ 3.26s 3.28s p=0.932 n=6
Bind Time 1.54s (± 0.27%) 1.54s (± 0.58%) ~ 1.53s 1.55s p=0.787 n=6
Check Time 2.81s (± 0.43%) 2.82s (± 0.41%) ~ 2.80s 2.83s p=0.458 n=6
Emit Time 0.08s (± 0.00%) 0.08s (± 0.00%) ~ 0.08s 0.08s p=1.000 n=6
Total Time 7.69s (± 0.27%) 7.70s (± 0.19%) ~ 7.68s 7.72s p=0.195 n=6
System info unknown
Hosts
  • node (v18.15.0, x64)
Scenarios
  • Angular - node (v18.15.0, x64)
  • Compiler-Unions - node (v18.15.0, x64)
  • Monaco - node (v18.15.0, x64)
  • TFS - node (v18.15.0, x64)
  • material-ui - node (v18.15.0, x64)
  • xstate - node (v18.15.0, x64)
Benchmark Name Iterations
Current pr 6
Baseline baseline 6

tsserver

Comparison Report - baseline..pr
Metric baseline pr Delta Best Worst p-value
Compiler-UnionsTSServer - node (v18.15.0, x64)
Req 1 - updateOpen 2,338ms (± 0.98%) 2,351ms (± 0.80%) ~ 2,324ms 2,374ms p=0.336 n=6
Req 2 - geterr 5,400ms (± 1.32%) 5,430ms (± 1.16%) ~ 5,350ms 5,491ms p=0.810 n=6
Req 3 - references 322ms (± 0.57%) 317ms (± 1.51%) ~ 313ms 325ms p=0.062 n=6
Req 4 - navto 279ms (± 1.01%) 275ms (± 1.25%) ~ 271ms 280ms p=0.067 n=6
Req 5 - completionInfo count 1,356 (± 0.00%) 1,356 (± 0.00%) ~ 1,356 1,356 p=1.000 n=6
Req 5 - completionInfo 83ms (± 4.51%) 88ms (± 4.82%) 🔻+5ms (+ 6.26%) 82ms 94ms p=0.043 n=6
CompilerTSServer - node (v18.15.0, x64)
Req 1 - updateOpen 2,476ms (± 0.81%) 2,454ms (± 1.28%) ~ 2,401ms 2,487ms p=0.229 n=6
Req 2 - geterr 4,115ms (± 1.73%) 4,015ms (± 1.41%) -99ms (- 2.42%) 3,986ms 4,129ms p=0.030 n=6
Req 3 - references 344ms (± 1.50%) 349ms (± 1.19%) ~ 341ms 352ms p=0.062 n=6
Req 4 - navto 285ms (± 0.36%) 282ms (± 0.27%) -3ms (- 1.00%) 281ms 283ms p=0.004 n=6
Req 5 - completionInfo count 1,518 (± 0.00%) 1,518 (± 0.00%) ~ 1,518 1,518 p=1.000 n=6
Req 5 - completionInfo 87ms (± 5.30%) 87ms (± 5.63%) ~ 77ms 89ms p=0.655 n=6
xstateTSServer - node (v18.15.0, x64)
Req 1 - updateOpen 2,599ms (± 0.52%) 2,587ms (± 0.65%) ~ 2,564ms 2,609ms p=0.470 n=6
Req 2 - geterr 1,686ms (± 2.18%) 1,675ms (± 1.59%) ~ 1,650ms 1,710ms p=0.471 n=6
Req 3 - references 110ms (±10.29%) 106ms (± 7.42%) ~ 102ms 122ms p=0.935 n=6
Req 4 - navto 364ms (± 0.57%) 365ms (± 0.14%) ~ 365ms 366ms p=0.113 n=6
Req 5 - completionInfo count 2,073 (± 0.00%) 2,073 (± 0.00%) ~ 2,073 2,073 p=1.000 n=6
Req 5 - completionInfo 312ms (± 1.50%) 310ms (± 1.69%) ~ 300ms 316ms p=0.572 n=6
System info unknown
Hosts
  • node (v18.15.0, x64)
Scenarios
  • CompilerTSServer - node (v18.15.0, x64)
  • Compiler-UnionsTSServer - node (v18.15.0, x64)
  • xstateTSServer - node (v18.15.0, x64)
Benchmark Name Iterations
Current pr 6
Baseline baseline 6

Startup

Comparison Report - baseline..pr
Metric baseline pr Delta Best Worst p-value
tsc-startup - node (v18.15.0, x64)
Execution time 152.92ms (± 0.20%) 152.90ms (± 0.18%) ~ 151.75ms 156.83ms p=0.824 n=600
tsserver-startup - node (v18.15.0, x64)
Execution time 228.43ms (± 0.21%) 228.14ms (± 0.15%) -0.29ms (- 0.13%) 227.01ms 232.51ms p=0.000 n=600
tsserverlibrary-startup - node (v18.15.0, x64)
Execution time 229.69ms (± 0.18%) 229.71ms (± 0.21%) ~ 228.04ms 237.42ms p=0.726 n=600
typescript-startup - node (v18.15.0, x64)
Execution time 229.30ms (± 0.18%) 229.43ms (± 0.19%) +0.13ms (+ 0.06%) 227.50ms 235.75ms p=0.003 n=600
System info unknown
Hosts
  • node (v18.15.0, x64)
Scenarios
  • tsc-startup - node (v18.15.0, x64)
  • tsserver-startup - node (v18.15.0, x64)
  • tsserverlibrary-startup - node (v18.15.0, x64)
  • typescript-startup - node (v18.15.0, x64)
Benchmark Name Iterations
Current pr 6
Baseline baseline 6

Developer Information:

Download Benchmarks

@typescript-bot
Copy link
Collaborator

Hey @gabritto, the results of running the DT tests are ready.
Everything looks the same!
You can check the log here.

@gabritto
Copy link
Member

gabritto commented Dec 5, 2023

It seems some error has gone missing from lodash? #56313 (comment)
From a quick look at it, it doesn't look like the error should be there, but I don't know why it was or how it relates to this PR.

Also, this one does seem like a bug: #56313 (comment)

@typescript-bot
Copy link
Collaborator

@gabritto Here are the results of running the top-repos suite comparing main and refs/pull/56313/merge:

Something interesting changed - please have a look.

Details

StanGirard/quivr

1 of 2 projects failed to build with the old tsc and were ignored

frontend/tsconfig.json

@gabritto
Copy link
Member

gabritto commented Dec 6, 2023

@typescript-bot pack this

@typescript-bot
Copy link
Collaborator

typescript-bot commented Dec 6, 2023

Heya @gabritto, I've started to run the tarball bundle task on this PR at 6e7aa4d. You can monitor the build here.

@typescript-bot
Copy link
Collaborator

typescript-bot commented Dec 6, 2023

Hey @gabritto, I've packed this into an installable tgz. You can install it for testing by referencing it in your package.json like so:

{
    "devDependencies": {
        "typescript": "https://typescript.visualstudio.com/cf7ac146-d525-443c-b23c-0d58337efebc/_apis/build/builds/158981/artifacts?artifactName=tgz&fileId=8AC808353628C7DE522DFF5B18DFAB6350BDAA72DFB77C8E094D81D546E7802902&fileName=/typescript-5.4.0-insiders.20231206.tgz"
    }
}

and then running npm install.


There is also a playground for this build and an npm module you can use via "typescript": "npm:@typescript-deploys/pr-build@5.4.0-pr-56313-12".;

}

function hasParentWithAssignmentsMarked(node: Node) {
return !!findAncestor(node.parent, node => (isFunctionLike(node) || isCatchClause(node)) && !!(getNodeLinks(node).flags & NodeCheckFlags.AssignmentsMarked));
}

function markNodeAssignments(node: Node) {
function markNodeAssignments(node: Node): true | undefined {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we not return in this function, the way it was before? I think it's not really necessary and potentially confusing, since we don't use the results returned by this function.

Copy link
Contributor Author

@Andarist Andarist Dec 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since we don't use the results returned by this function.

It is used by forEachChild. This return acts as an early return for its iteration.

That being said, I probably need to mark both individual symbols as assigned or not together with the aggregate information on the root declaration to fix the regression found here.

A minimal repro case for this regression:

declare function useRouter(): {
    push: (href: string) => void;
}

type SidebarFooterButtonProps = {
  href?: string;
  onClick?: () => void;
};

export const SidebarFooterButton = ({
  href,
  onClick,
}: SidebarFooterButtonProps): JSX.Element => {
  const router = useRouter();

  if (href !== undefined) {
    onClick = () => {
      void router.push(href);
    };
  }

  return (
    <button type="button" onClick={onClick} />
  );
};

We still want to narrow "const" parameters and only turn off the dependent parameter narrowing if some of the relevant symbols are reassigned - so we need to keep track of both (or well, derive the aggregate information on demand from the root declaration's symbols)

So If I do any of those, this confusing return will go way :p

@@ -28921,7 +28918,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
while (
flowContainer !== declarationContainer && (flowContainer.kind === SyntaxKind.FunctionExpression ||
flowContainer.kind === SyntaxKind.ArrowFunction || isObjectLiteralOrClassExpressionMethodOrAccessor(flowContainer)) &&
(isConstantVariable(localOrExportSymbol) && type !== autoArrayType || isParameter && !isSymbolAssigned(localOrExportSymbol))
(isConstantVariable(localOrExportSymbol) && type !== autoArrayType || isParameter && !isSomeSymbolAssigned(rootDeclaration))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like the change to isSymbolAssigned behavior, to aggregate isAssigned at the root declaration level, might not be the correct thing to do here, for this particular usage of isSymbolAssigned, as evidenced by this breaking change: #56313 (comment).

Maybe we want to keep marking symbols with isAssigned, and also aggregate that info at the root declaration level, since getNarrowedTypeOfSymbol needs the aggregate info but checkIdentifier needs the symbol info.

Here's a more minimal repro of the break linked above:

function ff({ a, b }: { a: string | undefined, b: () => void }) {
  if (a !== undefined) {
    b = () => {
      const x: string = a;
    }
  }
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Heh, I really need to start reading through all of the existing comments at once instead of reading through them one by one. It would save me a few minutes here 😅

@@ -28766,7 +28762,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
const contextualSignature = getContextualSignature(func);
if (contextualSignature && contextualSignature.parameters.length === 1 && signatureHasRestParameter(contextualSignature)) {
const restType = getReducedApparentType(instantiateType(getTypeOfSymbol(contextualSignature.parameters[0]), getInferenceContext(func)?.nonFixingMapper));
if (restType.flags & TypeFlags.Union && everyType(restType, isTupleType) && !isSymbolAssigned(symbol)) {
if (restType.flags & TypeFlags.Union && everyType(restType, isTupleType) && !isSomeSymbolAssigned(declaration)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this case here is not fixed by aggregating isAssigned at root declaration level, since the root declaration will be a parameter declaration, but the other dependent parameter could have been reassigned:

const test2: (...args: [1, 2] | [3, 4]) => void = (x, y) => {
  if (Math.random()) {
    y = 2;
  }
  if (y === 2) {
    x
    // ^? (parameter) x: 1
  }
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A great catch! The "dependent root declaration" might come from the context... I'll have to think about this and recheck how this kind of narrowing is handled today.

@Andarist Andarist requested a review from gabritto December 7, 2023 22:45
@@ -5278,7 +5278,7 @@ export function isPushOrUnshiftIdentifier(node: Identifier) {
*
* @internal
*/
export function isParameterDeclaration(node: Declaration): boolean {
export function isParameterDeclaration(node: Declaration): node is ParameterDeclaration {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you forget to undo this maybe? I think despite the terribly misleading name, this function is not meant to return whether node is ParameterDeclaration.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Everything else seems good now and I'll approve and merge once this parameter declaration thing is gone.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, totally! I could swear that I have reverted this... but I guess I didn't 😬 I fixed this just now.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, this definitely is not a type guard. See also #52283.

@gabritto
Copy link
Member

@typescript-bot user test this
@typescript-bot test top100
@typescript-bot perf test this

@typescript-bot
Copy link
Collaborator

typescript-bot commented Dec 11, 2023

Heya @gabritto, I've started to run the diff-based user code test suite on this PR at bbda1ed. You can monitor the build here.

Update: The results are in!

@typescript-bot
Copy link
Collaborator

typescript-bot commented Dec 11, 2023

Heya @gabritto, I've started to run the regular perf test suite on this PR at bbda1ed. You can monitor the build here.

@typescript-bot
Copy link
Collaborator

typescript-bot commented Dec 11, 2023

Heya @gabritto, I've started to run the diff-based top-repos suite on this PR at bbda1ed. You can monitor the build here.

Update: The results are in!

@typescript-bot
Copy link
Collaborator

@gabritto Here are the results of running the user test suite comparing main and refs/pull/56313/merge:

There were infrastructure failures potentially unrelated to your change:

  • 1 instance of "Package install failed"

Otherwise...

Something interesting changed - please have a look.

Details

puppeteer

packages/browsers/test/src/tsconfig.json

@typescript-bot
Copy link
Collaborator

@gabritto Here are the results of running the top-repos suite comparing main and refs/pull/56313/merge:

Everything looks good!

@gabritto gabritto merged commit af36878 into microsoft:main Dec 11, 2023
c0sta pushed a commit to c0sta/TypeScript that referenced this pull request Dec 20, 2023
@Andarist Andarist deleted the fix/depenent-parameters-invalidation branch January 1, 2025 10:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
For Backlog Bug PRs that fix a backlog bug
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

Not all parameter assignments prevent incorrect dependent narrowings
4 participants