Skip to content

Improve narrowing by boolean discriminant without strictNullChecks #55291

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

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

Andarist
Copy link
Contributor

@Andarist Andarist commented Aug 7, 2023

fixes #10564

⚠️ this only affects strictNullChecks: false, I'm not even sure if this is the right fix or if the issue is supposed to get fixed (it's an old one). The non-strict rules are confusing to me :p

@typescript-bot typescript-bot added the For Backlog Bug PRs that fix a backlog bug label Aug 7, 2023
@@ -1205,7 +1205,7 @@ export const enum TypeFacts {
FalseStrictFacts = BaseBooleanStrictFacts | Falsy,
FalseFacts = BaseBooleanFacts,
TrueStrictFacts = BaseBooleanStrictFacts | Truthy,
TrueFacts = BaseBooleanFacts | Truthy,
TrueFacts = (BaseBooleanFacts & ~Falsy) | Truthy,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

if this is too broad of a change then perhaps the fix (if it's even desired today) could be moved closer to this narrowType callback:
https://github.dev/microsoft/TypeScript/blob/e936eb13d2900f21d79553c32a704307c7ad03dd/src/compiler/checker.ts#L27121

@@ -286,7 +286,7 @@ var resultIsString3 = null === undefined ? exprString1 : exprString2;
var resultIsObject3 = true || false ? exprIsObject1 : exprIsObject2;
>resultIsObject3 : Object
>true || false ? exprIsObject1 : exprIsObject2 : Object
>true || false : boolean
>true || false : true
Copy link
Member

Choose a reason for hiding this comment

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

This is the wrong result under strictNullChecks: false

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Could u ELI5 how to reason about strictNullChecks: false in situations like this?

Copy link
Member

Choose a reason for hiding this comment

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

Any value can be falsy due to being null / undefined

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I know that from the assignability PoV but that doesnt help me explain your expected result here. Shouldnt intrinsic value like true be non-falsy?

Where is the line if the referenced issue got labeled as a bug?

Copy link
Member

Choose a reason for hiding this comment

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

A value of type true might be inhabited by null. Obviously the expression true itself isn't, but that's not really under analysis

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If the compiler has to always account for the fact that the value might be inhabited by null then wouldn't it mean that one of the examples from the referenced issue shouldn't typecheck (and it does typecheck today)?

type Result = { success: true }
            | { success: false, error: string }

function handleError2(res: Result) {
    if (res.success !== false) {
        return;
    }

    res.error; // OK, but shouldn't be?
}

I always thought that strictNullChecks: false means that things can be null/undefined at runtime but that the type-checker is meant to ignore this fact completely.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Either way - I pushed out an improved (but not cleaned up, code-wise) version of the fix for the linked issue. Please take a look if those semantics look any better.

Choose a reason for hiding this comment

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

I always thought that strictNullChecks: false means that things can be null/undefined at runtime but that the type-checker is meant to ignore this fact completely.

This is a point of discussion that comes up sometimes on Discord - strictNullChecks: false is basically a completely different type checker. The flag does a lot more than its name would suggest, changing inferences, narrowing, etc. in sometimes very unexpected ways, and all of it is more or less by design.

@Andarist Andarist changed the title Remove Falsy from TypeFacts.Truthy Improve narrowing by boolean discriminant without strictNullChecks Aug 7, 2023
@Andarist Andarist requested a review from RyanCavanaugh August 14, 2023 19:44
@DanielRosenwasser
Copy link
Member

@typescript-bot pack this
@typescript-bot test this
@typescript-bot test top300
@typescript-bot user test this
@typescript-bot run dt
@typescript-bot perf test this

@typescript-bot
Copy link
Collaborator

typescript-bot commented Aug 17, 2023

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

Update: The results are in!

@typescript-bot
Copy link
Collaborator

typescript-bot commented Aug 17, 2023

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

Update: The results are in!

@typescript-bot
Copy link
Collaborator

typescript-bot commented Aug 17, 2023

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

@typescript-bot
Copy link
Collaborator

typescript-bot commented Aug 17, 2023

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

Update: The results are in!

@typescript-bot
Copy link
Collaborator

typescript-bot commented Aug 17, 2023

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

Update: The results are in!

@typescript-bot
Copy link
Collaborator

typescript-bot commented Aug 17, 2023

Hey @DanielRosenwasser, 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/156632/artifacts?artifactName=tgz&fileId=8CA587E2291370203D7818CEC05F7525E71B7519D118B5689E9179C491BF852602&fileName=/typescript-5.3.0-insiders.20230817.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/[email protected]".;

@typescript-bot
Copy link
Collaborator

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

There were infrastructure failures potentially unrelated to your change:

  • 1 instance of "Unknown failure"
  • 1 instance of "Package install failed"

Otherwise...

Something interesting changed - please have a look.

Details

rxjs-src

/mnt/ts_downloads/rxjs-src/build.sh

  • [NEW] error TS2428: All declarations of 'WeakMap' must have identical type parameters.
    • /home/vsts/work/1/s/typescript-55291/lib/lib.es2015.collection.d.ts(62,11)
    • /home/vsts/work/1/s/typescript-55291/lib/lib.es2015.iterable.d.ts(162,11)
    • /home/vsts/work/1/s/typescript-55291/lib/lib.es2015.symbol.wellknown.d.ts(140,11)
    • /home/vsts/work/1/s/typescript-55291/lib/lib.es2015.collection.d.ts(62,11)
    • /home/vsts/work/1/s/typescript-55291/lib/lib.es2015.iterable.d.ts(162,11)
    • /home/vsts/work/1/s/typescript-55291/lib/lib.es2015.symbol.wellknown.d.ts(140,11)
    • /home/vsts/work/1/s/typescript-55291/lib/lib.es2015.collection.d.ts(62,11)
    • /home/vsts/work/1/s/typescript-55291/lib/lib.es2015.iterable.d.ts(162,11)
    • /home/vsts/work/1/s/typescript-55291/lib/lib.es2015.symbol.wellknown.d.ts(140,11)
    • /home/vsts/work/1/s/typescript-55291/lib/lib.es2015.collection.d.ts(62,11)
    • /home/vsts/work/1/s/typescript-55291/lib/lib.es2015.iterable.d.ts(162,11)
    • /home/vsts/work/1/s/typescript-55291/lib/lib.es2015.symbol.wellknown.d.ts(140,11)
    • /home/vsts/work/1/s/typescript-55291/lib/lib.es2015.collection.d.ts(62,11)
    • /home/vsts/work/1/s/typescript-55291/lib/lib.es2015.iterable.d.ts(162,11)
    • /home/vsts/work/1/s/typescript-55291/lib/lib.es2015.symbol.wellknown.d.ts(140,11)
  • [MISSING] error TS2428: All declarations of 'WeakMap' must have identical type parameters.
    • /home/vsts/work/1/s/typescript-main/lib/lib.es2015.collection.d.ts(62,11)
    • /home/vsts/work/1/s/typescript-main/lib/lib.es2015.iterable.d.ts(162,11)
    • /home/vsts/work/1/s/typescript-main/lib/lib.es2015.symbol.wellknown.d.ts(140,11)
    • /home/vsts/work/1/s/typescript-main/lib/lib.es2015.collection.d.ts(62,11)
    • /home/vsts/work/1/s/typescript-main/lib/lib.es2015.iterable.d.ts(162,11)
    • /home/vsts/work/1/s/typescript-main/lib/lib.es2015.symbol.wellknown.d.ts(140,11)
    • /home/vsts/work/1/s/typescript-main/lib/lib.es2015.collection.d.ts(62,11)
    • /home/vsts/work/1/s/typescript-main/lib/lib.es2015.iterable.d.ts(162,11)
    • /home/vsts/work/1/s/typescript-main/lib/lib.es2015.symbol.wellknown.d.ts(140,11)
    • /home/vsts/work/1/s/typescript-main/lib/lib.es2015.collection.d.ts(62,11)
    • /home/vsts/work/1/s/typescript-main/lib/lib.es2015.iterable.d.ts(162,11)
    • /home/vsts/work/1/s/typescript-main/lib/lib.es2015.symbol.wellknown.d.ts(140,11)
    • /home/vsts/work/1/s/typescript-main/lib/lib.es2015.collection.d.ts(62,11)
    • /home/vsts/work/1/s/typescript-main/lib/lib.es2015.iterable.d.ts(162,11)
    • /home/vsts/work/1/s/typescript-main/lib/lib.es2015.symbol.wellknown.d.ts(140,11)

@typescript-bot
Copy link
Collaborator

@DanielRosenwasser
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 (v16.17.1, x64)
Memory used 300,383k (± 0.01%) 300,367k (± 0.01%) ~ 300,350k 300,397k p=0.335 n=6
Parse Time 3.02s (± 0.25%) 3.02s (± 0.27%) ~ 3.01s 3.03s p=0.729 n=6
Bind Time 0.93s (± 0.00%) 0.93s (± 0.00%) ~ 0.93s 0.93s p=1.000 n=6
Check Time 9.49s (± 0.30%) 9.50s (± 0.26%) ~ 9.47s 9.53s p=0.418 n=6
Emit Time 7.62s (± 0.40%) 7.61s (± 0.26%) ~ 7.58s 7.63s p=0.418 n=6
Total Time 21.06s (± 0.23%) 21.06s (± 0.11%) ~ 21.03s 21.10s p=0.686 n=6
Compiler-Unions - node (v16.17.1, x64)
Memory used 193,884k (± 0.01%) 193,929k (± 0.02%) +45k (+ 0.02%) 193,872k 193,961k p=0.030 n=6
Parse Time 1.57s (± 1.05%) 1.59s (± 0.26%) +0.02s (+ 1.49%) 1.58s 1.59s p=0.006 n=6
Bind Time 0.79s (± 0.00%) 0.79s (± 0.52%) ~ 0.79s 0.80s p=0.405 n=6
Check Time 9.93s (± 0.28%) 9.95s (± 0.34%) ~ 9.89s 9.99s p=0.520 n=6
Emit Time 2.74s (± 0.36%) 2.74s (± 0.36%) ~ 2.73s 2.75s p=0.611 n=6
Total Time 15.02s (± 0.27%) 15.07s (± 0.25%) ~ 15.01s 15.12s p=0.106 n=6
Monaco - node (v16.17.1, x64)
Memory used 347,108k (± 0.01%) 347,129k (± 0.01%) ~ 347,089k 347,153k p=0.336 n=6
Parse Time 2.69s (± 0.31%) 2.69s (± 0.19%) ~ 2.68s 2.69s p=0.533 n=6
Bind Time 0.99s (± 0.41%) 0.99s (± 0.41%) ~ 0.98s 0.99s p=0.218 n=6
Check Time 7.92s (± 0.31%) 7.92s (± 0.37%) ~ 7.87s 7.96s p=0.683 n=6
Emit Time 4.26s (± 0.31%) 4.27s (± 0.53%) ~ 4.25s 4.31s p=0.743 n=6
Total Time 15.85s (± 0.17%) 15.86s (± 0.26%) ~ 15.79s 15.90s p=0.572 n=6
TFS - node (v16.17.1, x64)
Memory used 301,129k (± 0.01%) 301,136k (± 0.01%) ~ 301,107k 301,158k p=0.471 n=6
Parse Time 2.17s (± 0.56%) 2.18s (± 0.45%) ~ 2.16s 2.19s p=0.490 n=6
Bind Time 1.11s (± 0.37%) 1.10s (± 1.10%) ~ 1.08s 1.11s p=0.527 n=6
Check Time 7.25s (± 0.19%) 7.22s (± 0.41%) ~ 7.19s 7.26s p=0.124 n=6
Emit Time 3.98s (± 0.26%) 3.98s (± 0.19%) ~ 3.97s 3.99s p=0.273 n=6
Total Time 14.51s (± 0.19%) 14.48s (± 0.29%) ~ 14.42s 14.52s p=0.088 n=6
material-ui - node (v16.17.1, x64)
Memory used 479,445k (± 0.01%) 479,426k (± 0.00%) ~ 479,408k 479,436k p=0.470 n=6
Parse Time 3.15s (± 0.00%) 3.15s (± 0.26%) ~ 3.15s 3.17s p=0.176 n=6
Bind Time 0.91s (± 0.00%) 0.91s (± 0.00%) ~ 0.91s 0.91s p=1.000 n=6
Check Time 17.95s (± 0.19%) 17.96s (± 0.23%) ~ 17.92s 18.02s 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 22.02s (± 0.17%) 22.03s (± 0.18%) ~ 21.98s 22.08s p=0.629 n=6
xstate - node (v16.17.1, x64)
Memory used 542,783k (± 0.00%) 542,799k (± 0.01%) ~ 542,754k 542,864k p=0.575 n=6
Parse Time 3.70s (± 0.28%) 3.70s (± 0.20%) ~ 3.69s 3.71s p=0.348 n=6
Bind Time 1.40s (± 4.71%) 1.36s (± 3.97%) ~ 1.33s 1.47s p=0.283 n=6
Check Time 3.26s (± 2.65%) 3.31s (± 1.96%) ~ 3.18s 3.36s p=0.422 n=6
Emit Time 0.08s (± 0.00%) 0.08s (± 0.00%) ~ 0.08s 0.08s p=1.000 n=6
Total Time 8.44s (± 0.47%) 8.45s (± 0.32%) ~ 8.42s 8.49s p=0.520 n=6
System info unknown
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 pr 6
Baseline baseline 6

tsserver

Comparison Report - baseline..pr
Metric baseline pr Delta Best Worst p-value
Compiler-UnionsTSServer - node (v16.17.1, x64)
Req 1 - updateOpen 2,492ms (± 0.05%) 2,491ms (± 0.21%) ~ 2,481ms 2,496ms p=0.566 n=6
Req 2 - geterr 5,952ms (± 0.42%) 5,961ms (± 0.34%) ~ 5,939ms 5,988ms p=0.423 n=6
Req 3 - references 343ms (± 1.23%) 343ms (± 0.56%) ~ 341ms 346ms p=0.416 n=6
Req 4 - navto 278ms (± 1.10%) 280ms (± 0.87%) ~ 277ms 282ms p=0.254 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 (± 9.84%) 86ms (± 9.86%) ~ 75ms 93ms p=0.676 n=6
CompilerTSServer - node (v16.17.1, x64)
Req 1 - updateOpen 2,630ms (± 0.78%) 2,624ms (± 0.54%) ~ 2,606ms 2,640ms p=0.470 n=6
Req 2 - geterr 4,748ms (± 0.21%) 4,727ms (± 1.45%) ~ 4,588ms 4,763ms p=0.688 n=6
Req 3 - references 350ms (± 0.21%) 350ms (± 0.29%) ~ 349ms 352ms p=0.931 n=6
Req 4 - navto 269ms (± 0.60%) 271ms (± 0.98%) ~ 269ms 276ms p=0.244 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 77ms (± 4.37%) 78ms (± 2.75%) ~ 74ms 80ms p=0.931 n=6
xstateTSServer - node (v16.17.1, x64)
Req 1 - updateOpen 2,716ms (± 0.17%) 2,714ms (± 0.14%) ~ 2,710ms 2,720ms p=0.466 n=6
Req 2 - geterr 1,945ms (± 1.87%) 1,944ms (± 1.67%) ~ 1,878ms 1,965ms p=0.810 n=6
Req 3 - references 124ms (± 8.68%) 125ms (± 7.29%) ~ 114ms 137ms p=0.872 n=6
Req 4 - navto 355ms (± 0.85%) 353ms (± 0.34%) ~ 351ms 354ms p=0.324 n=6
Req 5 - completionInfo count 2,071 (± 0.00%) 2,071 (± 0.00%) ~ 2,071 2,071 p=1.000 n=6
Req 5 - completionInfo 319ms (± 2.45%) 319ms (± 2.53%) ~ 310ms 329ms p=0.872 n=6
System info unknown
Hosts
  • node (v16.17.1, x64)
Scenarios
  • CompilerTSServer - node (v16.17.1, x64)
  • Compiler-UnionsTSServer - node (v16.17.1, x64)
  • xstateTSServer - node (v16.17.1, 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 (v16.17.1, x64)
Execution time 155.51ms (± 0.18%) 155.50ms (± 0.18%) ~ 154.21ms 160.05ms p=0.484 n=600
tsserver-startup - node (v16.17.1, x64)
Execution time 230.88ms (± 0.14%) 230.65ms (± 0.14%) -0.24ms (- 0.10%) 229.64ms 235.36ms p=0.000 n=600
tsserverlibrary-startup - node (v16.17.1, x64)
Execution time 234.82ms (± 0.12%) 236.09ms (± 0.14%) +1.28ms (+ 0.54%) 234.87ms 242.59ms p=0.000 n=600
typescript-startup - node (v16.17.1, x64)
Execution time 235.96ms (± 0.14%) 235.81ms (± 0.12%) -0.15ms (- 0.06%) 234.49ms 239.58ms p=0.000 n=600
System info unknown
Hosts
  • node (v16.17.1, x64)
Scenarios
  • tsc-startup - node (v16.17.1, x64)
  • tsserver-startup - node (v16.17.1, x64)
  • tsserverlibrary-startup - node (v16.17.1, x64)
  • typescript-startup - node (v16.17.1, x64)
Benchmark Name Iterations
Current pr 6
Baseline baseline 6

Developer Information:

Download Benchmarks

@typescript-bot
Copy link
Collaborator

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

@typescript-bot
Copy link
Collaborator

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

Everything looks good!

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
Status: Waiting on reviewers
Development

Successfully merging this pull request may close these issues.

Strange boolean-discriminant narrowing with strictNullChecks off
5 participants