Skip to content

Check for strict subtypes and then regular subtypes in getNarrowedType #52984

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
merged 7 commits into from
Mar 3, 2023

Conversation

ahejlsberg
Copy link
Member

@ahejlsberg ahejlsberg commented Feb 26, 2023

Experiment to see the effects of first checking for strict subtypes and then checking for regular subtypes in getNarrowedType, and picking the asserted type only when it is a pure subtype of the original type.

First experiment checked only using the strict subtype relationship, but that introduces too many breaking changes (specifically caused by strict checking of signature arity and readonly properties).

Fixes #52827.

@typescript-bot typescript-bot added Author: Team For Milestone Bug PRs that fix a bug with a specific milestone labels Feb 26, 2023
@ahejlsberg
Copy link
Member Author

@typescript-bot test this
@typescript-bot user test this inline
@typescript-bot run dt
@typescript-bot test top100

@typescript-bot
Copy link
Collaborator

typescript-bot commented Feb 26, 2023

Heya @ahejlsberg, I've started to run the extended test suite on this PR at 0325f9d. You can monitor the build here.

@typescript-bot
Copy link
Collaborator

typescript-bot commented Feb 26, 2023

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

Update: The results are in!

@typescript-bot
Copy link
Collaborator

typescript-bot commented Feb 26, 2023

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

@typescript-bot
Copy link
Collaborator

typescript-bot commented Feb 26, 2023

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

Update: The results are in!

@typescript-bot
Copy link
Collaborator

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

Everything looks good!

@typescript-bot
Copy link
Collaborator

Heya @ahejlsberg, I've run the RWC suite on this PR - assuming you're on the TS core team, you can view the resulting diff here.

@jakebailey
Copy link
Member

@typescript-bot perf test this faster

@typescript-bot
Copy link
Collaborator

typescript-bot commented Feb 26, 2023

Heya @jakebailey, I've started to run the abridged perf test suite on this PR at 0325f9d. You can monitor the build here.

Update: The results are in!

@typescript-bot
Copy link
Collaborator

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

Here they are:

Comparison Report - main..52984

Metric main 52984 Delta Best Worst p-value
Angular - node (v16.17.1, x64)
Memory used 359,065k (± 0.00%) 359,052k (± 0.00%) ~ 359,035k 359,078k p=0.173 n=6
Parse Time 3.71s (± 0.41%) 3.71s (± 0.43%) ~ 3.70s 3.74s p=0.801 n=6
Bind Time 1.19s (± 0.34%) 1.19s (± 0.53%) ~ 1.18s 1.20s p=0.673 n=6
Check Time 9.45s (± 0.72%) 9.45s (± 0.51%) ~ 9.37s 9.51s p=0.935 n=6
Emit Time 7.92s (± 0.56%) 7.94s (± 0.58%) ~ 7.88s 8.01s p=0.332 n=6
Total Time 22.27s (± 0.40%) 22.29s (± 0.37%) ~ 22.18s 22.43s p=0.936 n=6
Compiler-Unions - node (v16.17.1, x64)
Memory used 191,378k (± 0.05%) 191,871k (± 0.66%) ~ 191,275k 194,463k p=0.936 n=6
Parse Time 1.58s (± 1.11%) 1.56s (± 0.78%) -0.02s (- 1.27%) 1.54s 1.57s p=0.046 n=6
Bind Time 0.82s (± 0.00%) 0.82s (± 0.50%) ~ 0.81s 0.82s p=0.405 n=6
Check Time 10.10s (± 0.32%) 10.01s (± 0.55%) -0.09s (- 0.89%) 9.94s 10.07s p=0.013 n=6
Emit Time 3.00s (± 0.69%) 3.01s (± 0.35%) ~ 2.99s 3.02s p=0.564 n=6
Total Time 15.49s (± 0.34%) 15.39s (± 0.41%) -0.10s (- 0.63%) 15.30s 15.45s p=0.029 n=6
Monaco - node (v16.17.1, x64)
Memory used 343,133k (± 0.00%) 343,125k (± 0.00%) ~ 343,098k 343,138k p=0.470 n=6
Parse Time 2.79s (± 0.49%) 2.79s (± 0.48%) ~ 2.77s 2.80s p=0.388 n=6
Bind Time 1.09s (± 1.51%) 1.08s (± 0.48%) ~ 1.08s 1.09s p=0.794 n=6
Check Time 7.69s (± 0.25%) 7.70s (± 0.57%) ~ 7.64s 7.76s p=0.625 n=6
Emit Time 4.45s (± 0.87%) 4.46s (± 0.76%) ~ 4.43s 4.52s p=0.686 n=6
Total Time 16.01s (± 0.37%) 16.02s (± 0.20%) ~ 15.98s 16.06s p=0.747 n=6
TFS - node (v16.17.1, x64)
Memory used 299,242k (± 0.01%) 299,244k (± 0.01%) ~ 299,208k 299,261k p=0.873 n=6
Parse Time 2.16s (± 0.82%) 2.16s (± 0.48%) ~ 2.15s 2.18s p=0.410 n=6
Bind Time 1.24s (± 1.22%) 1.24s (± 0.99%) ~ 1.22s 1.25s p=0.801 n=6
Check Time 7.18s (± 0.41%) 7.17s (± 0.53%) ~ 7.12s 7.22s p=0.809 n=6
Emit Time 4.34s (± 0.80%) 4.32s (± 0.66%) ~ 4.29s 4.35s p=0.295 n=6
Total Time 14.91s (± 0.49%) 14.89s (± 0.47%) ~ 14.79s 14.99s p=0.568 n=6
material-ui - node (v16.17.1, x64)
Memory used 475,653k (± 0.01%) 475,686k (± 0.01%) ~ 475,634k 475,779k p=0.230 n=6
Parse Time 3.29s (± 0.23%) 3.28s (± 0.31%) ~ 3.27s 3.30s p=0.351 n=6
Bind Time 0.96s (± 0.43%) 0.96s (± 0.54%) ~ 0.95s 0.96s p=0.595 n=6
Check Time 17.96s (± 0.49%) 17.98s (± 0.39%) ~ 17.92s 18.11s p=0.572 n=6
Emit Time 0.00s (± 0.00%) 0.00s (± 0.00%) ~ 0.00s 0.00s p=1.000 n=6
Total Time 22.21s (± 0.41%) 22.22s (± 0.31%) ~ 22.15s 22.35s p=0.683 n=6
xstate - node (v16.17.1, x64)
Memory used 545,824k (± 0.03%) 545,946k (± 0.04%) ~ 545,745k 546,256k p=0.378 n=6
Parse Time 4.29s (± 0.35%) 4.29s (± 0.55%) ~ 4.25s 4.32s p=1.000 n=6
Bind Time 1.76s (± 0.43%) 1.76s (± 0.29%) ~ 1.75s 1.76s p=0.784 n=6
Check Time 2.99s (± 0.37%) 2.99s (± 0.58%) ~ 2.96s 3.01s p=0.222 n=6
Emit Time 0.09s (± 0.00%) 0.09s (± 0.00%) ~ 0.09s 0.09s p=1.000 n=6
Total Time 9.12s (± 0.18%) 9.12s (± 0.27%) ~ 9.09s 9.16s p=0.808 n=6
System
Machine Namets-ci-ubuntu
Platformlinux 5.4.0-135-generic
Architecturex64
Available Memory16 GB
Available Memory15 GB
CPUs4 × Intel(R) Core(TM) i7-4770 CPU @ 3.40GHz
Hosts
  • node (v16.17.1, x64)
Scenarios
  • Angular - node (v16.17.1, x64)
  • Compiler-Unions - node (v16.17.1, x64)
  • Monaco - node (v16.17.1, x64)
  • TFS - node (v16.17.1, x64)
  • material-ui - node (v16.17.1, x64)
  • xstate - node (v16.17.1, x64)
Benchmark Name Iterations
Current 52984 6
Baseline main 6

Developer Information:

Download Benchmark

@typescript-bot
Copy link
Collaborator

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

Something interesting changed - please have a look.

Details

microsoft/vscode

4 of 53 projects failed to build with the old tsc and were ignored

src/tsconfig.tsec.json

@ahejlsberg ahejlsberg changed the title Use strictSubtypeRelation in getNarrowedType and narrow only for pure subtypes Use for strict subtypes and then regular subtypes in getNarrowedType Feb 26, 2023
@ahejlsberg ahejlsberg changed the title Use for strict subtypes and then regular subtypes in getNarrowedType Check for strict subtypes and then regular subtypes in getNarrowedType Feb 26, 2023
@ahejlsberg
Copy link
Member Author

@typescript-bot test this
@typescript-bot user test this inline
@typescript-bot run dt
@typescript-bot perf test faster
@typescript-bot test top100

@typescript-bot
Copy link
Collaborator

typescript-bot commented Feb 26, 2023

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

Update: The results are in!

@typescript-bot
Copy link
Collaborator

typescript-bot commented Feb 26, 2023

Heya @ahejlsberg, I've started to run the extended test suite on this PR at d737eee. You can monitor the build here.

@typescript-bot
Copy link
Collaborator

typescript-bot commented Feb 26, 2023

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

Update: The results are in!

@typescript-bot
Copy link
Collaborator

typescript-bot commented Feb 26, 2023

Heya @ahejlsberg, I've started to run the abridged perf test suite on this PR at d737eee. You can monitor the build here.

Update: The results are in!

@typescript-bot
Copy link
Collaborator

typescript-bot commented Feb 26, 2023

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

@typescript-bot
Copy link
Collaborator

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

Everything looks good!

@typescript-bot
Copy link
Collaborator

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

Here they are:

Comparison Report - main..52984

Metric main 52984 Delta Best Worst p-value
Angular - node (v16.17.1, x64)
Memory used 359,065k (± 0.00%) 359,068k (± 0.01%) ~ 359,016k 359,092k p=0.575 n=6
Parse Time 3.71s (± 0.41%) 3.71s (± 0.22%) ~ 3.70s 3.72s p=0.555 n=6
Bind Time 1.19s (± 0.34%) 1.19s (± 0.53%) ~ 1.18s 1.20s p=0.673 n=6
Check Time 9.45s (± 0.72%) 9.45s (± 0.27%) ~ 9.40s 9.47s p=0.324 n=6
Emit Time 7.92s (± 0.56%) 7.92s (± 0.52%) ~ 7.86s 7.96s p=1.000 n=6
Total Time 22.27s (± 0.40%) 22.26s (± 0.20%) ~ 22.21s 22.33s p=0.872 n=6
Compiler-Unions - node (v16.17.1, x64)
Memory used 191,378k (± 0.05%) 192,851k (± 0.53%) +1,472k (+ 0.77%) 192,379k 194,951k p=0.005 n=6
Parse Time 1.58s (± 1.11%) 1.55s (± 0.97%) -0.02s (- 1.48%) 1.54s 1.58s p=0.042 n=6
Bind Time 0.82s (± 0.00%) 0.82s (± 0.00%) ~ 0.82s 0.82s p=1.000 n=6
Check Time 10.10s (± 0.32%) 10.13s (± 0.67%) ~ 10.01s 10.22s p=0.077 n=6
Emit Time 3.00s (± 0.69%) 2.99s (± 0.80%) ~ 2.95s 3.02s p=0.739 n=6
Total Time 15.49s (± 0.34%) 15.50s (± 0.47%) ~ 15.38s 15.59s p=0.748 n=6
Monaco - node (v16.17.1, x64)
Memory used 343,133k (± 0.00%) 343,135k (± 0.00%) ~ 343,109k 343,145k p=0.810 n=6
Parse Time 2.79s (± 0.49%) 2.80s (± 0.43%) ~ 2.78s 2.81s p=0.191 n=6
Bind Time 1.09s (± 1.51%) 1.08s (± 0.38%) ~ 1.07s 1.08s p=0.245 n=6
Check Time 7.69s (± 0.25%) 7.67s (± 0.45%) ~ 7.63s 7.70s p=0.323 n=6
Emit Time 4.45s (± 0.87%) 4.42s (± 0.42%) ~ 4.39s 4.44s p=0.329 n=6
Total Time 16.01s (± 0.37%) 15.96s (± 0.34%) ~ 15.89s 16.03s p=0.228 n=6
TFS - node (v16.17.1, x64)
Memory used 299,242k (± 0.01%) 299,254k (± 0.01%) ~ 299,230k 299,292k p=0.810 n=6
Parse Time 2.16s (± 0.82%) 2.15s (± 0.62%) ~ 2.13s 2.16s p=0.498 n=6
Bind Time 1.24s (± 1.22%) 1.25s (± 0.44%) ~ 1.24s 1.25s p=0.342 n=6
Check Time 7.18s (± 0.41%) 7.16s (± 0.56%) ~ 7.11s 7.20s p=0.332 n=6
Emit Time 4.34s (± 0.80%) 4.34s (± 0.99%) ~ 4.30s 4.42s p=0.686 n=6
Total Time 14.91s (± 0.49%) 14.89s (± 0.49%) ~ 14.82s 15.02s p=0.518 n=6
material-ui - node (v16.17.1, x64)
Memory used 475,653k (± 0.01%) 475,667k (± 0.01%) ~ 475,616k 475,756k p=0.378 n=6
Parse Time 3.29s (± 0.23%) 3.28s (± 0.46%) ~ 3.27s 3.31s p=0.318 n=6
Bind Time 0.96s (± 0.43%) 0.96s (± 0.66%) ~ 0.95s 0.97s p=0.673 n=6
Check Time 17.96s (± 0.49%) 18.08s (± 0.41%) ~ 17.96s 18.18s p=0.064 n=6
Emit Time 0.00s (± 0.00%) 0.00s (± 0.00%) ~ 0.00s 0.00s p=1.000 n=6
Total Time 22.21s (± 0.41%) 22.32s (± 0.35%) ~ 22.19s 22.41s p=0.078 n=6
xstate - node (v16.17.1, x64)
Memory used 545,824k (± 0.03%) 545,834k (± 0.01%) ~ 545,769k 545,963k p=0.810 n=6
Parse Time 4.29s (± 0.35%) 4.29s (± 0.37%) ~ 4.26s 4.30s p=0.808 n=6
Bind Time 1.76s (± 0.43%) 1.76s (± 0.36%) ~ 1.75s 1.77s p=0.718 n=6
Check Time 2.99s (± 0.37%) 3.00s (± 0.45%) ~ 2.99s 3.03s p=0.067 n=6
Emit Time 0.09s (± 0.00%) 0.09s (± 0.00%) ~ 0.09s 0.09s p=1.000 n=6
Total Time 9.12s (± 0.18%) 9.14s (± 0.22%) ~ 9.12s 9.17s p=0.225 n=6
System
Machine Namets-ci-ubuntu
Platformlinux 5.4.0-135-generic
Architecturex64
Available Memory16 GB
Available Memory15 GB
CPUs4 × Intel(R) Core(TM) i7-4770 CPU @ 3.40GHz
Hosts
  • node (v16.17.1, x64)
Scenarios
  • Angular - node (v16.17.1, x64)
  • Compiler-Unions - node (v16.17.1, x64)
  • Monaco - node (v16.17.1, x64)
  • TFS - node (v16.17.1, x64)
  • material-ui - node (v16.17.1, x64)
  • xstate - node (v16.17.1, x64)
Benchmark Name Iterations
Current 52984 6
Baseline main 6

Developer Information:

Download Benchmark

@typescript-bot
Copy link
Collaborator

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

Everything looks good!

@jakebailey
Copy link
Member

And, the answer is probably no (because it's risky), but, given the 5.0 regressions people are reporting, I'm somewhat curious if this is something we should backport before stable 5.0. But, I assume not.

@ahejlsberg
Copy link
Member Author

@jakebailey You can see some of them here.

@ahejlsberg
Copy link
Member Author

I think we should consider bringing this one into 5.0.

@jakebailey jakebailey added this to the TypeScript 5.0.2 milestone Mar 2, 2023
@MichaelMitchell-at
Copy link
Contributor

MichaelMitchell-at commented Mar 3, 2023

I think we should consider bringing this one into 5.0.

Original reporter of #50916 here. I tried out #52282 again in our codebase and while it does address the original issue, it introduced a regression elsewhere so this would still block us from upgrading to TS 5.0. I've tried out the fix in this PR locally and it seems to resolve both issues, so it'd be great if this could make it into TS 5.0.

The new regression if curious

type DistributedKeyOf<T> = T extends unknown ? keyof T : never;

type NarrowByKeyValue<ObjT, KeyT extends PropertyKey, ValueT> = ObjT extends unknown
    ? KeyT extends keyof ObjT
        ? ValueT extends ObjT[KeyT]
            ? ObjT & Readonly<Record<KeyT, ValueT>>
            : never
        : never
    : never;

type NarrowByDeepValue<ObjT, DeepPathT, ValueT> = DeepPathT extends readonly [
    infer Head extends DistributedKeyOf<ObjT>,
]
    ? NarrowByKeyValue<ObjT, Head, ValueT>
    : DeepPathT extends readonly [infer Head extends DistributedKeyOf<ObjT>, ...infer Rest]
    ? NarrowByKeyValue<ObjT, Head, NarrowByDeepValue<NonNullable<ObjT[Head]>, Rest, ValueT>>
    : never;


declare function doesValueAtDeepPathSatisfy<
    ObjT extends object,
    const DeepPathT extends ReadonlyArray<number | string>,
    ValueT,
>(
    obj: ObjT,
    deepPath: DeepPathT,
    predicate: (arg: unknown) => arg is ValueT,
): obj is NarrowByDeepValue<ObjT, DeepPathT, ValueT>;


type Foo = {value: {type: 'A'}; a?: number} | {value: {type: 'B'}; b?: number};

declare function isA(arg: unknown): arg is 'A';
declare function isB(arg: unknown): arg is 'B';

declare function assert(condition: boolean): asserts condition;

function test1(foo: Foo): {value: {type: 'A'}; a?: number} {
    assert(doesValueAtDeepPathSatisfy(foo, ['value', 'type'], isA));
    return foo;
}

function test2(foo: Foo): {value: {type: 'A'}; a?: number} {
    assert(!doesValueAtDeepPathSatisfy(foo, ['value', 'type'], isB));
    return foo;
}

@ahejlsberg
Copy link
Member Author

@MichaelMitchell-at Good to hear this PR fixes the issues. Meanwhile, would you mind updating the regression code above with the definitions of the missing functions so we can have an additional repro.

@MichaelMitchell-at
Copy link
Contributor

@MichaelMitchell-at Good to hear this PR fixes the issues. Meanwhile, would you mind updating the regression code above with the definitions of the missing functions so we can have an additional repro.

Ok, I'll need to refactor a bit to remove some internal dependencies

@chriskrycho
Copy link

This also fixes a regression in Ember's internal type test suite for TS 5.1 (no issue on 5.0) shaped like this:

function example(vals: Array<unknown> | MyCollection<unknown>): number {
  if (Array.isArray(vals)) {
    return vals.length;
    //     ^^^^ has type `Array<any>`
  } else {
    // ❌ type error (erroneous!)
    return vals.collectionSize;
    //     ^^^^ has type `Array<unknown> | MyCollection<unknown>`
  }
}

With this PR, this is back to behaving the way it did in v5.0 and earlier. 👍🏼

@MichaelMitchell-at
Copy link
Contributor

@ahejlsberg updated

@ahejlsberg
Copy link
Member Author

@MichaelMitchell-at Much appreciated. Will add as a test case.

@ahejlsberg
Copy link
Member Author

@chriskrycho I take it you mean this PR brings it back to behaving like 4.9 and earlier, right?

@ahejlsberg
Copy link
Member Author

Additional repro added in latest commit.

@chriskrycho
Copy link

chriskrycho commented Mar 3, 2023

@ahejlsberg Possibly I missed up my bisection, but in my testing, I thought I confirmed that the 5.0 RC worked and 5.1 did not. I can dig further (though not till Monday at the earliest).

@ahejlsberg ahejlsberg merged commit 6823559 into main Mar 3, 2023
@ahejlsberg ahejlsberg deleted the fix52827 branch March 3, 2023 23:56
@jakebailey
Copy link
Member

@typescript-bot cherry-pick this to release-5.0

@typescript-bot
Copy link
Collaborator

typescript-bot commented Mar 3, 2023

Heya @jakebailey, I've started to run the task to cherry-pick this into release-5.0 on this PR at 8bb30e2. You can monitor the build here.

@typescript-bot
Copy link
Collaborator

Hey @jakebailey, I've opened #53085 for you.

typescript-bot pushed a commit to typescript-bot/TypeScript that referenced this pull request Mar 4, 2023
Component commits:
b3d3ec9 Use strictSubtypeRelation in getNarrowedType and narrow only for pure subtypes

0325f9d Accept new baselines

3df807f First check for strict subtypes, then check for regular subtypes

d737eee Accept new baselines

9b2d602 Add tests

9ea8a55 Accept new baselines

8bb30e2 Add another repro
DanielRosenwasser pushed a commit that referenced this pull request Mar 7, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Author: Team For Milestone Bug PRs that fix a bug with a specific milestone
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Improvement to getNarrowedType changes lodash's isArray
6 participants