Skip to content
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

'in' should not operate on primitive types #41928

Closed
wants to merge 8 commits into from

Conversation

jonhue
Copy link
Contributor

@jonhue jonhue commented Dec 11, 2020

Fixes #41317

To address the issue I had to disallow values of types that are assignable to TypeFlags.TypeParameter from being used as the right argument to the in operator. Along the way, I also stopped allowing values whose type is assignable to TypeFlags.Conditional or TypeFlags.Substitution.

With this change all right arguments to in whose type is assignable to a primitive type, immediately lead to an error.

This change led to three test case failures:

  • inOperatorWithValidOperands
  • keyofAndIndexedAccess
  • conditionalTypeDoesntSpinForever

I presume that in case we want to pursue this change we will want to alter these test cases to explicitly annotate right arguments to in as objects. For the moment, I accepted the new baselines of these failing tests.

I'm also wondering if I should include the new test case I added (inDoesNotOperateOnPrimitiveTypes) in inOperatorWithValidOperands.

Also, we would probably have to change the error message.

Please let me know if any of this looks wrong to you!

@typescript-bot typescript-bot added the For Milestone Bug PRs that fix a bug with a specific milestone label Dec 11, 2020
@DanielRosenwasser
Copy link
Member

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

@typescript-bot
Copy link
Collaborator

typescript-bot commented Dec 11, 2020

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

Update: The results are in!

@typescript-bot
Copy link
Collaborator

typescript-bot commented Dec 11, 2020

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

@typescript-bot
Copy link
Collaborator

typescript-bot commented Dec 11, 2020

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

@typescript-bot
Copy link
Collaborator

typescript-bot commented Dec 11, 2020

Heya @DanielRosenwasser, I've started to run the parallelized community code test suite on this PR at 8c7ca65. You can monitor the build here.

@typescript-bot
Copy link
Collaborator

typescript-bot commented Dec 11, 2020

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

@typescript-bot
Copy link
Collaborator

typescript-bot commented Dec 11, 2020

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/90988/artifacts?artifactName=tgz&fileId=44951D0E343057C7BDCC504B923A539F03964455294B11DCAA7884517B908BC702&fileName=/typescript-4.2.0-insiders.20201211.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
The results of the perf run you requested are in!

Here they are:

Comparison Report - master..41928

Metric master 41928 Delta Best Worst
Angular - node (v10.16.3, x64)
Memory used 344,532k (± 0.02%) 344,577k (± 0.02%) +44k (+ 0.01%) 344,339k 344,681k
Parse Time 2.00s (± 0.75%) 1.98s (± 0.54%) -0.02s (- 1.00%) 1.95s 2.00s
Bind Time 0.83s (± 0.48%) 0.83s (± 0.63%) -0.00s (- 0.24%) 0.82s 0.84s
Check Time 4.98s (± 0.45%) 4.97s (± 0.62%) -0.01s (- 0.10%) 4.93s 5.05s
Emit Time 5.39s (± 1.10%) 5.33s (± 0.57%) -0.06s (- 1.04%) 5.28s 5.41s
Total Time 13.19s (± 0.51%) 13.10s (± 0.44%) -0.09s (- 0.65%) 13.00s 13.29s
Compiler-Unions - node (v10.16.3, x64)
Memory used 205,381k (± 0.03%) 205,346k (± 0.04%) -35k (- 0.02%) 205,056k 205,479k
Parse Time 0.79s (± 0.59%) 0.79s (± 0.89%) +0.00s (+ 0.13%) 0.78s 0.81s
Bind Time 0.50s (± 1.15%) 0.50s (± 0.80%) -0.00s (- 0.20%) 0.49s 0.51s
Check Time 11.95s (± 0.83%) 12.22s (± 1.09%) +0.26s (+ 2.20%) 11.85s 12.50s
Emit Time 2.32s (± 1.09%) 2.36s (± 1.68%) +0.04s (+ 1.81%) 2.26s 2.44s
Total Time 15.56s (± 0.66%) 15.87s (± 1.06%) +0.30s (+ 1.95%) 15.40s 16.23s
Monaco - node (v10.16.3, x64)
Memory used 354,886k (± 0.02%) 354,869k (± 0.02%) -16k (- 0.00%) 354,696k 355,014k
Parse Time 1.60s (± 0.68%) 1.61s (± 0.78%) +0.01s (+ 0.50%) 1.58s 1.64s
Bind Time 0.73s (± 0.65%) 0.73s (± 0.91%) +0.01s (+ 0.83%) 0.72s 0.75s
Check Time 5.13s (± 0.49%) 5.13s (± 0.25%) -0.00s (- 0.02%) 5.10s 5.16s
Emit Time 2.80s (± 0.34%) 2.79s (± 0.74%) -0.02s (- 0.57%) 2.75s 2.83s
Total Time 10.26s (± 0.33%) 10.26s (± 0.29%) -0.00s (- 0.00%) 10.21s 10.34s
TFS - node (v10.16.3, x64)
Memory used 307,922k (± 0.01%) 307,915k (± 0.01%) -7k (- 0.00%) 307,834k 308,058k
Parse Time 1.24s (± 0.78%) 1.24s (± 0.72%) -0.00s (- 0.32%) 1.22s 1.26s
Bind Time 0.68s (± 0.85%) 0.69s (± 0.69%) +0.00s (+ 0.59%) 0.68s 0.70s
Check Time 4.58s (± 0.44%) 4.57s (± 0.53%) -0.01s (- 0.20%) 4.53s 4.66s
Emit Time 2.94s (± 1.21%) 2.94s (± 0.73%) +0.01s (+ 0.20%) 2.90s 2.98s
Total Time 9.44s (± 0.61%) 9.44s (± 0.44%) -0.00s (- 0.02%) 9.37s 9.57s
material-ui - node (v10.16.3, x64)
Memory used 489,538k (± 0.01%) 489,534k (± 0.01%) -4k (- 0.00%) 489,408k 489,673k
Parse Time 2.06s (± 0.43%) 2.06s (± 0.29%) -0.00s (- 0.00%) 2.05s 2.08s
Bind Time 0.65s (± 0.56%) 0.66s (± 0.98%) +0.00s (+ 0.61%) 0.64s 0.67s
Check Time 13.67s (± 0.82%) 13.61s (± 0.79%) -0.06s (- 0.42%) 13.49s 13.97s
Emit Time 0.00s (± 0.00%) 0.00s (± 0.00%) 0.00s ( NaN%) 0.00s 0.00s
Total Time 16.39s (± 0.71%) 16.33s (± 0.66%) -0.06s (- 0.34%) 16.19s 16.69s
Angular - node (v12.1.0, x64)
Memory used 322,356k (± 0.02%) 322,270k (± 0.08%) -86k (- 0.03%) 321,234k 322,526k
Parse Time 1.96s (± 0.42%) 1.98s (± 1.19%) +0.02s (+ 0.77%) 1.95s 2.06s
Bind Time 0.82s (± 1.01%) 0.83s (± 2.19%) +0.01s (+ 1.47%) 0.81s 0.88s
Check Time 4.87s (± 0.38%) 4.91s (± 0.90%) +0.04s (+ 0.90%) 4.83s 5.05s
Emit Time 5.50s (± 0.52%) 5.54s (± 0.72%) +0.04s (+ 0.76%) 5.46s 5.64s
Total Time 13.15s (± 0.33%) 13.25s (± 0.71%) +0.11s (+ 0.82%) 13.12s 13.54s
Compiler-Unions - node (v12.1.0, x64)
Memory used 191,562k (± 0.05%) 191,539k (± 0.05%) -23k (- 0.01%) 191,281k 191,731k
Parse Time 0.78s (± 0.38%) 0.78s (± 0.83%) -0.00s (- 0.51%) 0.77s 0.80s
Bind Time 0.50s (± 1.04%) 0.50s (± 0.44%) +0.00s (+ 0.40%) 0.50s 0.51s
Check Time 10.88s (± 1.15%) 10.92s (± 1.14%) +0.04s (+ 0.34%) 10.65s 11.15s
Emit Time 2.37s (± 0.64%) 2.36s (± 0.61%) -0.00s (- 0.21%) 2.34s 2.40s
Total Time 14.53s (± 0.95%) 14.56s (± 0.88%) +0.03s (+ 0.23%) 14.30s 14.80s
Monaco - node (v12.1.0, x64)
Memory used 337,053k (± 0.01%) 337,004k (± 0.02%) -50k (- 0.01%) 336,815k 337,065k
Parse Time 1.58s (± 0.57%) 1.58s (± 0.70%) +0.00s (+ 0.13%) 1.57s 1.61s
Bind Time 0.71s (± 0.63%) 0.71s (± 1.12%) +0.00s (+ 0.56%) 0.70s 0.73s
Check Time 4.91s (± 0.41%) 4.94s (± 0.43%) +0.03s (+ 0.63%) 4.89s 4.98s
Emit Time 2.86s (± 0.48%) 2.86s (± 0.65%) +0.01s (+ 0.21%) 2.82s 2.91s
Total Time 10.05s (± 0.25%) 10.09s (± 0.34%) +0.04s (+ 0.42%) 10.02s 10.16s
TFS - node (v12.1.0, x64)
Memory used 292,136k (± 0.02%) 292,213k (± 0.01%) +77k (+ 0.03%) 292,115k 292,282k
Parse Time 1.25s (± 0.80%) 1.26s (± 0.78%) +0.00s (+ 0.40%) 1.24s 1.29s
Bind Time 0.65s (± 0.73%) 0.66s (± 0.91%) +0.00s (+ 0.46%) 0.64s 0.67s
Check Time 4.53s (± 0.39%) 4.52s (± 0.53%) -0.02s (- 0.35%) 4.46s 4.59s
Emit Time 2.97s (± 0.55%) 2.99s (± 1.06%) +0.02s (+ 0.74%) 2.93s 3.07s
Total Time 9.40s (± 0.32%) 9.42s (± 0.58%) +0.01s (+ 0.15%) 9.33s 9.56s
material-ui - node (v12.1.0, x64)
Memory used 467,358k (± 0.07%) 467,141k (± 0.09%) -217k (- 0.05%) 466,295k 467,742k
Parse Time 2.08s (± 0.56%) 2.08s (± 0.59%) +0.00s (+ 0.14%) 2.05s 2.11s
Bind Time 0.64s (± 0.87%) 0.65s (± 0.90%) +0.00s (+ 0.78%) 0.64s 0.66s
Check Time 12.19s (± 1.06%) 12.23s (± 0.98%) +0.04s (+ 0.32%) 11.94s 12.52s
Emit Time 0.00s (± 0.00%) 0.00s (± 0.00%) 0.00s ( NaN%) 0.00s 0.00s
Total Time 14.92s (± 0.93%) 14.96s (± 0.85%) +0.05s (+ 0.32%) 14.64s 15.26s
Angular - node (v8.9.0, x64)
Memory used 347,106k (± 0.02%) 347,130k (± 0.02%) +24k (+ 0.01%) 347,030k 347,334k
Parse Time 2.52s (± 0.51%) 2.52s (± 0.35%) 0.00s ( 0.00%) 2.50s 2.53s
Bind Time 0.86s (± 0.79%) 0.86s (± 1.00%) -0.00s (- 0.35%) 0.84s 0.89s
Check Time 5.61s (± 0.74%) 5.62s (± 0.56%) +0.00s (+ 0.05%) 5.54s 5.70s
Emit Time 6.27s (± 1.11%) 6.33s (± 1.44%) +0.06s (+ 0.94%) 6.08s 6.52s
Total Time 15.26s (± 0.66%) 15.32s (± 0.79%) +0.05s (+ 0.36%) 15.00s 15.64s
Compiler-Unions - node (v8.9.0, x64)
Memory used 213,161k (± 0.02%) 213,170k (± 0.03%) +9k (+ 0.00%) 213,024k 213,279k
Parse Time 0.95s (± 0.65%) 0.95s (± 0.74%) 0.00s ( 0.00%) 0.94s 0.97s
Bind Time 0.58s (± 0.65%) 0.58s (± 0.86%) +0.00s (+ 0.17%) 0.57s 0.59s
Check Time 14.75s (± 0.71%) 14.76s (± 1.12%) +0.02s (+ 0.10%) 14.37s 15.11s
Emit Time 2.76s (± 1.87%) 2.75s (± 1.99%) -0.01s (- 0.43%) 2.61s 2.82s
Total Time 19.03s (± 0.62%) 19.04s (± 1.13%) +0.01s (+ 0.04%) 18.51s 19.43s
Monaco - node (v8.9.0, x64)
Memory used 358,819k (± 0.02%) 358,805k (± 0.01%) -14k (- 0.00%) 358,714k 358,915k
Parse Time 1.93s (± 0.40%) 1.93s (± 0.36%) 0.00s ( 0.00%) 1.91s 1.94s
Bind Time 0.91s (± 0.49%) 0.91s (± 0.80%) -0.00s (- 0.00%) 0.89s 0.92s
Check Time 5.67s (± 0.57%) 5.68s (± 0.50%) +0.01s (+ 0.14%) 5.64s 5.75s
Emit Time 3.41s (± 0.31%) 3.44s (± 0.49%) +0.03s (+ 0.85%) 3.39s 3.47s
Total Time 11.92s (± 0.37%) 11.96s (± 0.27%) +0.04s (+ 0.30%) 11.86s 12.03s
TFS - node (v8.9.0, x64)
Memory used 310,540k (± 0.01%) 310,502k (± 0.02%) -39k (- 0.01%) 310,423k 310,631k
Parse Time 1.57s (± 0.31%) 1.57s (± 0.48%) +0.00s (+ 0.06%) 1.55s 1.59s
Bind Time 0.69s (± 0.69%) 0.69s (± 0.53%) -0.00s (- 0.15%) 0.68s 0.69s
Check Time 5.34s (± 0.48%) 5.34s (± 0.51%) -0.00s (- 0.04%) 5.26s 5.39s
Emit Time 2.97s (± 0.69%) 2.96s (± 0.70%) -0.01s (- 0.24%) 2.89s 2.99s
Total Time 10.56s (± 0.37%) 10.56s (± 0.39%) -0.00s (- 0.05%) 10.46s 10.64s
material-ui - node (v8.9.0, x64)
Memory used 496,663k (± 0.01%) 496,622k (± 0.01%) -41k (- 0.01%) 496,565k 496,670k
Parse Time 2.50s (± 0.65%) 2.50s (± 0.30%) +0.00s (+ 0.00%) 2.48s 2.51s
Bind Time 0.81s (± 1.53%) 0.81s (± 1.32%) -0.00s (- 0.25%) 0.77s 0.82s
Check Time 18.20s (± 1.25%) 18.20s (± 0.93%) -0.00s (- 0.02%) 17.79s 18.67s
Emit Time 0.00s (± 0.00%) 0.00s (± 0.00%) 0.00s ( NaN%) 0.00s 0.00s
Total Time 21.51s (± 1.13%) 21.50s (± 0.81%) -0.00s (- 0.02%) 21.09s 21.97s
Angular - node (v8.9.0, x86)
Memory used 199,152k (± 0.03%) 199,119k (± 0.02%) -33k (- 0.02%) 199,006k 199,225k
Parse Time 2.42s (± 0.82%) 2.44s (± 0.80%) +0.02s (+ 0.87%) 2.40s 2.49s
Bind Time 1.02s (± 1.04%) 1.01s (± 0.88%) -0.00s (- 0.20%) 1.00s 1.04s
Check Time 5.06s (± 0.81%) 5.07s (± 0.83%) +0.01s (+ 0.20%) 5.01s 5.22s
Emit Time 6.13s (± 0.86%) 6.12s (± 0.61%) -0.02s (- 0.28%) 6.05s 6.22s
Total Time 14.63s (± 0.58%) 14.64s (± 0.53%) +0.01s (+ 0.08%) 14.47s 14.81s
Compiler-Unions - node (v8.9.0, x86)
Memory used 128,131k (± 0.03%) 128,158k (± 0.03%) +27k (+ 0.02%) 128,076k 128,238k
Parse Time 0.96s (± 0.49%) 0.96s (± 0.62%) +0.00s (+ 0.21%) 0.95s 0.98s
Bind Time 0.49s (± 1.01%) 0.49s (± 0.91%) -0.00s (- 0.61%) 0.48s 0.50s
Check Time 13.89s (± 0.98%) 13.95s (± 0.98%) +0.06s (+ 0.40%) 13.78s 14.46s
Emit Time 2.66s (± 0.86%) 2.64s (± 1.16%) -0.02s (- 0.79%) 2.57s 2.73s
Total Time 18.01s (± 0.79%) 18.04s (± 0.80%) +0.04s (+ 0.21%) 17.88s 18.58s
Monaco - node (v8.9.0, x86)
Memory used 203,252k (± 0.02%) 203,275k (± 0.02%) +22k (+ 0.01%) 203,231k 203,386k
Parse Time 1.97s (± 0.70%) 1.97s (± 0.58%) -0.00s (- 0.10%) 1.94s 2.00s
Bind Time 0.71s (± 0.52%) 0.72s (± 0.81%) +0.00s (+ 0.28%) 0.71s 0.73s
Check Time 5.79s (± 1.21%) 5.85s (± 0.44%) +0.06s (+ 1.07%) 5.80s 5.92s
Emit Time 2.77s (± 3.03%) 2.76s (± 1.01%) -0.01s (- 0.33%) 2.70s 2.82s
Total Time 11.24s (± 0.35%) 11.29s (± 0.36%) +0.05s (+ 0.46%) 11.20s 11.40s
TFS - node (v8.9.0, x86)
Memory used 177,643k (± 0.02%) 177,661k (± 0.02%) +18k (+ 0.01%) 177,606k 177,764k
Parse Time 1.61s (± 1.22%) 1.61s (± 1.19%) 0.00s ( 0.00%) 1.59s 1.67s
Bind Time 0.65s (± 0.89%) 0.65s (± 0.34%) +0.00s (+ 0.15%) 0.65s 0.66s
Check Time 4.90s (± 0.87%) 4.89s (± 0.61%) -0.02s (- 0.37%) 4.84s 4.97s
Emit Time 2.82s (± 0.74%) 2.82s (± 0.69%) -0.00s (- 0.11%) 2.77s 2.86s
Total Time 9.99s (± 0.47%) 9.97s (± 0.37%) -0.02s (- 0.22%) 9.89s 10.05s
material-ui - node (v8.9.0, x86)
Memory used 279,659k (± 0.01%) 279,667k (± 0.01%) +8k (+ 0.00%) 279,585k 279,755k
Parse Time 2.55s (± 0.64%) 2.54s (± 0.38%) -0.01s (- 0.47%) 2.51s 2.55s
Bind Time 0.75s (± 7.28%) 0.72s (± 5.44%) 🟩-0.03s (- 4.02%) 0.67s 0.86s
Check Time 16.43s (± 0.43%) 16.61s (± 0.75%) +0.18s (+ 1.08%) 16.32s 16.88s
Emit Time 0.00s (± 0.00%) 0.00s (± 0.00%) 0.00s ( NaN%) 0.00s 0.00s
Total Time 19.73s (± 0.42%) 19.87s (± 0.79%) +0.14s (+ 0.71%) 19.54s 20.29s
System
Machine Namets-ci-ubuntu
Platformlinux 4.4.0-197-generic
Architecturex64
Available Memory16 GB
Available Memory11 GB
CPUs4 × Intel(R) Core(TM) i7-4770 CPU @ 3.40GHz
Hosts
  • node (v10.16.3, x64)
  • node (v12.1.0, x64)
  • node (v8.9.0, x64)
  • node (v8.9.0, x86)
Scenarios
  • Angular - node (v10.16.3, x64)
  • Angular - node (v12.1.0, x64)
  • Angular - node (v8.9.0, x64)
  • Angular - node (v8.9.0, x86)
  • Compiler-Unions - node (v10.16.3, x64)
  • Compiler-Unions - node (v12.1.0, x64)
  • Compiler-Unions - node (v8.9.0, x64)
  • Compiler-Unions - node (v8.9.0, x86)
  • Monaco - node (v10.16.3, x64)
  • Monaco - node (v12.1.0, x64)
  • Monaco - node (v8.9.0, x64)
  • Monaco - node (v8.9.0, x86)
  • TFS - node (v10.16.3, x64)
  • TFS - node (v12.1.0, x64)
  • TFS - node (v8.9.0, x64)
  • TFS - node (v8.9.0, x86)
  • material-ui - node (v10.16.3, x64)
  • material-ui - node (v12.1.0, x64)
  • material-ui - node (v8.9.0, x64)
  • material-ui - node (v8.9.0, x86)
Benchmark Name Iterations
Current 41928 10
Baseline master 10

@typescript-bot
Copy link
Collaborator

The user suite test run you requested has finished and failed. I've opened a PR with the baseline diff from master.

@DanielRosenwasser
Copy link
Member

DanielRosenwasser commented Dec 11, 2020

The user test suite indicates 4 new breaks in Fluent UI.

https://github.com/microsoft/fluentui/blob/c298abf7b7f48d660737a5f96a488f1a0820a322/packages/codemods/src/helpers/maybe.ts#L31

https://github.com/microsoft/fluentui/blob/c298abf7b7f48d660737a5f96a488f1a0820a322/packages/codemods/src/helpers/maybe.ts#L72

https://github.com/microsoft/fluentui/blob/master/packages/utilities/src/warn/warnDeprecations.ts#L14

https://github.com/microsoft/fluentui/blob/c298abf7b7f48d660737a5f96a488f1a0820a322/packages/utilities/src/warn/warnConditionallyRequiredProps.ts#L21


https://github.com/typescript-bot/TypeScript/pull/114/files#diff-02fa25d51ee84a35829f43b04a84da8bce4668eed9b38642fc37504afa10004bR671-R676

@fluentui/codemods: [XX:XX:XX XM] x src/helpers/maybe.ts:31:53 - error TS2361: The right-hand side of an 'in' expression must be of type 'any', an object type or a type parameter.
@fluentui/codemods: 31       if (typeof val === 'object' && '__isMaybe' in val) {
@fluentui/codemods:                                                        ~~~
@fluentui/codemods: src/helpers/maybe.ts:72:38 - error TS2361: The right-hand side of an 'in' expression must be of type 'any', an object type or a type parameter.
@fluentui/codemods: 72       if (!value || !('__isMaybe' in value)) {
@fluentui/codemods:                                         ~~~~~

https://github.com/typescript-bot/TypeScript/pull/114/files#diff-02fa25d51ee84a35829f43b04a84da8bce4668eed9b38642fc37504afa10004bR784-R790

@fluentui/utilities: src/warn/warnConditionallyRequiredProps.ts:21:33 - error TS2361: The right-hand side of an 'in' expression must be of type 'any', an object type or a type parameter.
@fluentui/utilities: 21       if (!(requiredPropName in props)) {
@fluentui/utilities:                                    ~~~~~
@fluentui/utilities: src/warn/warnDeprecations.ts:14:32 - error TS2361: The right-hand side of an 'in' expression must be of type 'any', an object type or a type parameter.
@fluentui/utilities: 14       if (props && propName in props) {
@fluentui/utilities:                                   ~~~~~
@fluentui/utilities: Found 10 errors.

@RyanCavanaugh
Copy link
Member

   if (typeof val === 'object' && '__isMaybe' in val) {

This error is actually correct - val could be null - but boy are we going to get bug reports about this. Maybe we need to special-case the error message.

@DanielRosenwasser
Copy link
Member

Well...ish. The type is defined as T | undefined. I'd argue that the breaks on bare type parameters is undesirable (that's what we'd decided on in the original issue).

@DanielRosenwasser
Copy link
Member

DanielRosenwasser commented Dec 11, 2020

But in this instance, you're probably right, this type should probably account for a Maybe<string | null> and it doesn't.

@jonhue
Copy link
Contributor Author

jonhue commented Dec 12, 2020

@RyanCavanaugh @DanielRosenwasser

This error is actually correct - val could be null - but boy are we going to get bug reports about this. Maybe we need to special-case the error message.

I agree, the error message needs some tweaking. If we wanted to exclude null and undefined from these checks that would be easy enough. But at the moment, I'm not quite certain if that's what we want to do to "fix" these issues that seem like sincere problems. One thing we could do though is to only check for null and undefined in strict mode. In that case, do we have a function or a boolean flag we carry around to check whether we are in strict mode?

The user test suite indicates 4 new breaks in Fluent UI.

Just out of curiosity and because the contributing file didn't mention these tests, how do they relate to the main test suite? 🙂
Are they merely to get an overview of how a change would affect the TypeScript ecosystem of libraries?

Copy link
Member

@andrewbranch andrewbranch left a comment

Choose a reason for hiding this comment

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

This error is actually correct - val could be null - but boy are we going to get bug reports about this. Maybe we need to special-case the error message.

Well, the real problem with this is that since type parameters don’t narrow, you can’t make this error go away by adding the correct fix:

- if (typeof val === 'object' && '__isMaybe' in val) {
+ if (val && typeof val === 'object' && '__isMaybe' in val) {

which I think is @DanielRosenwasser’s point about implementing a more conservative fix with respect to unconstrained type parameters. So if I understand correctly, @jonhue your invalidHasKey example test actually should not error. We’re only trying to catch cases that are definitely errors, like

function f<T extends string | number>(val: T) {
  '__isMaybe' in val;
}

Comment on lines 30005 to 30006
if (!allTypesAssignableToKind(rightType, TypeFlags.NonPrimitive | TypeFlags.InstantiableNonPrimitive) ||
rightType.immediateBaseConstraint && allTypesAssignableToKind(rightType.immediateBaseConstraint, TypeFlags.Primitive)) {
Copy link
Contributor Author

@jonhue jonhue Dec 16, 2020

Choose a reason for hiding this comment

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

Thank you all for the comments and hints!

I wasn't able to extract the information we need directly from rightTypes flags. Both alsoValidHasKey and invalidHasKey generate the same type flag for the right type. I guess this is to be expected though as we're looking at constraints on the type to identify whether this is a valid/invalid use of the in operator.

I'm not familiar enough with the codebase though to be able to tell whether we can always expect rightType.immediateBaseConstraint to be present in the cases we care about.

Copy link
Member

Choose a reason for hiding this comment

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

I’m not 100% on this, but I believe all you need is

Suggested change
if (!allTypesAssignableToKind(rightType, TypeFlags.NonPrimitive | TypeFlags.InstantiableNonPrimitive) ||
rightType.immediateBaseConstraint && allTypesAssignableToKind(rightType.immediateBaseConstraint, TypeFlags.Primitive)) {
if (!allTypesAssignableToKind(getApparentType(rightType), TypeFlags.NonPrimitive)) {

getApparentType will get the (resolved) base constraint if the type is instantiable (the immediate base constraint might also be instantiable), which means the result should never be instantiable, so you no longer have to check for InstantiableNonPrimitive. But make sure I’m not making stuff up by running the tests, and someone else on the team should double check my understanding here too.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@andrewbranch I tried this out both comparing against NonPrimitive and comparing against NonPrimitive | InstantiableNonPrimitive, but both approaches lead to many scenarios where don't throw an error even though we should.

For example the following is accepted:

var b1: number;
var rb1 = 'x' in b1;

@jonhue jonhue requested a review from andrewbranch December 16, 2020 13:40
@DanielRosenwasser
Copy link
Member

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

@typescript-bot
Copy link
Collaborator

typescript-bot commented Dec 16, 2020

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

Update: The results are in!

@typescript-bot
Copy link
Collaborator

typescript-bot commented Dec 16, 2020

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

@typescript-bot
Copy link
Collaborator

typescript-bot commented Dec 16, 2020

Heya @DanielRosenwasser, I've started to run the parallelized community code test suite on this PR at d2cd9b1. You can monitor the build here.

@typescript-bot
Copy link
Collaborator

typescript-bot commented Dec 16, 2020

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

@typescript-bot
Copy link
Collaborator

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

Here they are:

Comparison Report - master..41928

Metric master 41928 Delta Best Worst
Angular - node (v10.16.3, x64)
Memory used 345,114k (± 0.02%) 345,087k (± 0.02%) -27k (- 0.01%) 344,963k 345,268k
Parse Time 1.99s (± 0.70%) 1.98s (± 0.55%) -0.01s (- 0.50%) 1.95s 2.01s
Bind Time 0.83s (± 0.88%) 0.83s (± 0.88%) 0.00s ( 0.00%) 0.81s 0.84s
Check Time 4.98s (± 0.57%) 5.00s (± 0.43%) +0.01s (+ 0.22%) 4.94s 5.04s
Emit Time 5.35s (± 0.80%) 5.33s (± 0.38%) -0.02s (- 0.37%) 5.27s 5.36s
Total Time 13.15s (± 0.55%) 13.13s (± 0.22%) -0.02s (- 0.14%) 13.08s 13.20s
Compiler-Unions - node (v10.16.3, x64)
Memory used 205,328k (± 0.10%) 205,424k (± 0.06%) +95k (+ 0.05%) 204,944k 205,608k
Parse Time 0.79s (± 1.15%) 0.80s (± 0.62%) +0.00s (+ 0.63%) 0.79s 0.81s
Bind Time 0.50s (± 1.30%) 0.50s (± 0.80%) +0.00s (+ 0.20%) 0.49s 0.51s
Check Time 12.07s (± 0.65%) 12.11s (± 0.65%) +0.04s (+ 0.32%) 11.98s 12.38s
Emit Time 2.36s (± 1.83%) 2.33s (± 0.67%) -0.02s (- 1.02%) 2.29s 2.36s
Total Time 15.72s (± 0.63%) 15.74s (± 0.55%) +0.02s (+ 0.14%) 15.60s 16.03s
Monaco - node (v10.16.3, x64)
Memory used 354,965k (± 0.01%) 354,986k (± 0.02%) +21k (+ 0.01%) 354,796k 355,181k
Parse Time 1.60s (± 0.58%) 1.60s (± 0.59%) +0.00s (+ 0.19%) 1.58s 1.62s
Bind Time 0.72s (± 0.50%) 0.72s (± 0.51%) +0.00s (+ 0.14%) 0.72s 0.73s
Check Time 5.15s (± 0.34%) 5.12s (± 0.40%) -0.03s (- 0.49%) 5.07s 5.16s
Emit Time 2.82s (± 0.64%) 2.83s (± 0.59%) +0.01s (+ 0.43%) 2.79s 2.87s
Total Time 10.29s (± 0.33%) 10.28s (± 0.33%) -0.01s (- 0.10%) 10.21s 10.36s
TFS - node (v10.16.3, x64)
Memory used 307,933k (± 0.02%) 307,950k (± 0.01%) +18k (+ 0.01%) 307,873k 308,064k
Parse Time 1.23s (± 0.54%) 1.24s (± 0.70%) +0.01s (+ 0.73%) 1.23s 1.26s
Bind Time 0.68s (± 0.53%) 0.68s (± 0.95%) -0.00s (- 0.29%) 0.66s 0.69s
Check Time 4.58s (± 0.53%) 4.61s (± 0.45%) +0.03s (+ 0.70%) 4.56s 4.65s
Emit Time 2.96s (± 0.59%) 2.94s (± 0.89%) -0.02s (- 0.68%) 2.89s 3.00s
Total Time 9.45s (± 0.35%) 9.47s (± 0.44%) +0.02s (+ 0.22%) 9.38s 9.54s
material-ui - node (v10.16.3, x64)
Memory used 489,815k (± 0.01%) 489,842k (± 0.02%) +27k (+ 0.01%) 489,683k 490,064k
Parse Time 2.06s (± 0.37%) 2.06s (± 0.48%) -0.00s (- 0.19%) 2.04s 2.08s
Bind Time 0.65s (± 1.02%) 0.65s (± 0.91%) +0.00s (+ 0.15%) 0.64s 0.67s
Check Time 13.74s (± 0.78%) 13.64s (± 0.62%) -0.10s (- 0.71%) 13.50s 13.83s
Emit Time 0.00s (± 0.00%) 0.00s (± 0.00%) 0.00s ( NaN%) 0.00s 0.00s
Total Time 16.45s (± 0.69%) 16.35s (± 0.50%) -0.10s (- 0.59%) 16.21s 16.54s
Angular - node (v12.1.0, x64)
Memory used 322,814k (± 0.02%) 322,781k (± 0.02%) -33k (- 0.01%) 322,645k 322,876k
Parse Time 1.96s (± 0.65%) 1.96s (± 0.76%) +0.00s (+ 0.05%) 1.93s 2.01s
Bind Time 0.82s (± 1.10%) 0.82s (± 0.91%) +0.00s (+ 0.25%) 0.80s 0.83s
Check Time 4.93s (± 0.86%) 4.89s (± 0.48%) -0.04s (- 0.77%) 4.84s 4.94s
Emit Time 5.54s (± 0.48%) 5.51s (± 0.59%) -0.03s (- 0.63%) 5.45s 5.59s
Total Time 13.25s (± 0.43%) 13.18s (± 0.40%) -0.06s (- 0.49%) 13.05s 13.29s
Compiler-Unions - node (v12.1.0, x64)
Memory used 191,513k (± 0.08%) 191,529k (± 0.07%) +16k (+ 0.01%) 191,164k 191,753k
Parse Time 0.77s (± 0.62%) 0.78s (± 0.63%) +0.00s (+ 0.39%) 0.77s 0.79s
Bind Time 0.50s (± 0.99%) 0.50s (± 0.60%) +0.00s (+ 0.40%) 0.49s 0.50s
Check Time 10.78s (± 0.72%) 10.86s (± 0.89%) +0.09s (+ 0.84%) 10.70s 11.12s
Emit Time 2.35s (± 0.84%) 2.37s (± 1.78%) +0.02s (+ 0.64%) 2.29s 2.46s
Total Time 14.40s (± 0.52%) 14.51s (± 0.85%) +0.11s (+ 0.76%) 14.27s 14.79s
Monaco - node (v12.1.0, x64)
Memory used 337,048k (± 0.02%) 337,055k (± 0.02%) +7k (+ 0.00%) 336,895k 337,206k
Parse Time 1.58s (± 0.64%) 1.59s (± 0.78%) +0.01s (+ 0.95%) 1.57s 1.63s
Bind Time 0.71s (± 0.67%) 0.71s (± 0.56%) +0.00s (+ 0.28%) 0.70s 0.72s
Check Time 4.92s (± 0.64%) 4.94s (± 0.46%) +0.02s (+ 0.43%) 4.88s 4.98s
Emit Time 2.87s (± 0.57%) 2.88s (± 0.91%) +0.01s (+ 0.49%) 2.84s 2.97s
Total Time 10.06s (± 0.40%) 10.12s (± 0.37%) +0.05s (+ 0.51%) 10.06s 10.21s
TFS - node (v12.1.0, x64)
Memory used 292,149k (± 0.02%) 292,138k (± 0.01%) -10k (- 0.00%) 292,057k 292,215k
Parse Time 1.25s (± 0.56%) 1.26s (± 0.55%) +0.01s (+ 0.48%) 1.24s 1.27s
Bind Time 0.65s (± 0.80%) 0.66s (± 1.26%) +0.00s (+ 0.77%) 0.64s 0.68s
Check Time 4.50s (± 0.39%) 4.51s (± 0.58%) +0.01s (+ 0.31%) 4.46s 4.56s
Emit Time 2.94s (± 0.81%) 2.96s (± 0.67%) +0.02s (+ 0.68%) 2.92s 3.02s
Total Time 9.34s (± 0.34%) 9.39s (± 0.40%) +0.05s (+ 0.50%) 9.27s 9.46s
material-ui - node (v12.1.0, x64)
Memory used 467,797k (± 0.06%) 467,774k (± 0.06%) -23k (- 0.00%) 466,751k 467,969k
Parse Time 2.08s (± 0.56%) 2.08s (± 0.43%) +0.01s (+ 0.43%) 2.06s 2.10s
Bind Time 0.65s (± 0.56%) 0.65s (± 1.02%) +0.00s (+ 0.62%) 0.63s 0.66s
Check Time 12.19s (± 0.89%) 12.15s (± 0.77%) -0.05s (- 0.39%) 11.99s 12.37s
Emit Time 0.00s (± 0.00%) 0.00s (± 0.00%) 0.00s ( NaN%) 0.00s 0.00s
Total Time 14.92s (± 0.76%) 14.88s (± 0.63%) -0.04s (- 0.23%) 14.72s 15.08s
Angular - node (v8.9.0, x64)
Memory used 347,638k (± 0.03%) 347,689k (± 0.02%) +52k (+ 0.01%) 347,541k 347,841k
Parse Time 2.52s (± 0.55%) 2.51s (± 0.39%) -0.01s (- 0.48%) 2.49s 2.53s
Bind Time 0.86s (± 0.67%) 0.86s (± 0.86%) +0.00s (+ 0.00%) 0.85s 0.89s
Check Time 5.62s (± 0.57%) 5.63s (± 0.48%) +0.01s (+ 0.27%) 5.57s 5.69s
Emit Time 6.34s (± 1.01%) 6.34s (± 0.46%) -0.00s (- 0.02%) 6.27s 6.40s
Total Time 15.34s (± 0.57%) 15.35s (± 0.26%) +0.01s (+ 0.05%) 15.26s 15.42s
Compiler-Unions - node (v8.9.0, x64)
Memory used 213,196k (± 0.02%) 213,192k (± 0.02%) -4k (- 0.00%) 213,074k 213,284k
Parse Time 0.95s (± 0.63%) 0.96s (± 1.21%) +0.00s (+ 0.10%) 0.94s 0.98s
Bind Time 0.58s (± 1.18%) 0.58s (± 0.89%) +0.01s (+ 0.87%) 0.57s 0.60s
Check Time 14.90s (± 1.28%) 14.85s (± 0.98%) -0.05s (- 0.36%) 14.60s 15.19s
Emit Time 2.77s (± 1.77%) 2.78s (± 1.98%) +0.02s (+ 0.54%) 2.61s 2.84s
Total Time 19.20s (± 1.13%) 19.17s (± 0.92%) -0.03s (- 0.17%) 18.81s 19.56s
Monaco - node (v8.9.0, x64)
Memory used 358,820k (± 0.02%) 358,790k (± 0.01%) -30k (- 0.01%) 358,712k 358,851k
Parse Time 1.93s (± 0.38%) 1.93s (± 0.18%) -0.00s (- 0.16%) 1.92s 1.93s
Bind Time 0.91s (± 0.73%) 0.91s (± 0.64%) -0.00s (- 0.33%) 0.89s 0.92s
Check Time 5.70s (± 0.43%) 5.69s (± 0.34%) -0.01s (- 0.25%) 5.64s 5.72s
Emit Time 3.42s (± 0.55%) 3.41s (± 0.46%) -0.00s (- 0.12%) 3.39s 3.45s
Total Time 11.96s (± 0.29%) 11.94s (± 0.24%) -0.02s (- 0.18%) 11.87s 12.01s
TFS - node (v8.9.0, x64)
Memory used 310,501k (± 0.01%) 310,555k (± 0.02%) +54k (+ 0.02%) 310,429k 310,691k
Parse Time 1.57s (± 0.64%) 1.57s (± 0.71%) +0.01s (+ 0.51%) 1.56s 1.61s
Bind Time 0.68s (± 0.54%) 0.69s (± 0.69%) +0.00s (+ 0.29%) 0.68s 0.70s
Check Time 5.31s (± 0.28%) 5.35s (± 0.59%) +0.04s (+ 0.79%) 5.25s 5.39s
Emit Time 2.97s (± 0.62%) 2.97s (± 0.64%) -0.01s (- 0.24%) 2.91s 3.00s
Total Time 10.53s (± 0.13%) 10.58s (± 0.39%) +0.05s (+ 0.46%) 10.49s 10.64s
material-ui - node (v8.9.0, x64)
Memory used 497,043k (± 0.01%) 497,049k (± 0.02%) +6k (+ 0.00%) 496,905k 497,249k
Parse Time 2.50s (± 0.61%) 2.50s (± 0.64%) +0.00s (+ 0.00%) 2.47s 2.55s
Bind Time 0.82s (± 1.20%) 0.81s (± 1.85%) -0.02s (- 1.95%) 0.78s 0.85s
Check Time 18.21s (± 0.76%) 18.31s (± 0.98%) +0.10s (+ 0.53%) 17.99s 18.72s
Emit Time 0.00s (± 0.00%) 0.00s (± 0.00%) 0.00s ( NaN%) 0.00s 0.00s
Total Time 21.53s (± 0.66%) 21.61s (± 0.82%) +0.08s (+ 0.36%) 21.27s 22.04s
Angular - node (v8.9.0, x86)
Memory used 199,414k (± 0.03%) 199,443k (± 0.02%) +29k (+ 0.01%) 199,361k 199,528k
Parse Time 2.43s (± 0.69%) 2.45s (± 1.10%) +0.02s (+ 0.91%) 2.40s 2.53s
Bind Time 1.01s (± 0.61%) 1.02s (± 0.83%) +0.01s (+ 1.19%) 1.00s 1.04s
Check Time 5.07s (± 0.43%) 5.14s (± 1.39%) +0.06s (+ 1.22%) 5.04s 5.40s
Emit Time 6.11s (± 0.86%) 6.15s (± 1.11%) +0.04s (+ 0.67%) 5.95s 6.30s
Total Time 14.62s (± 0.34%) 14.76s (± 0.94%) +0.14s (+ 0.96%) 14.45s 15.18s
Compiler-Unions - node (v8.9.0, x86)
Memory used 128,137k (± 0.04%) 128,151k (± 0.03%) +13k (+ 0.01%) 128,091k 128,251k
Parse Time 0.96s (± 0.42%) 0.97s (± 0.94%) +0.01s (+ 0.83%) 0.95s 0.99s
Bind Time 0.50s (± 1.11%) 0.50s (± 1.55%) -0.00s (- 0.60%) 0.48s 0.52s
Check Time 13.95s (± 0.39%) 13.99s (± 0.53%) +0.04s (+ 0.28%) 13.87s 14.17s
Emit Time 2.65s (± 2.36%) 2.63s (± 1.61%) -0.03s (- 1.02%) 2.57s 2.78s
Total Time 18.07s (± 0.47%) 18.08s (± 0.54%) +0.02s (+ 0.09%) 17.92s 18.31s
Monaco - node (v8.9.0, x86)
Memory used 203,270k (± 0.03%) 203,279k (± 0.02%) +8k (+ 0.00%) 203,213k 203,397k
Parse Time 1.97s (± 0.53%) 1.99s (± 0.77%) +0.03s (+ 1.32%) 1.95s 2.03s
Bind Time 0.71s (± 0.84%) 0.71s (± 0.69%) -0.00s (- 0.14%) 0.70s 0.72s
Check Time 5.82s (± 0.35%) 5.75s (± 1.71%) -0.07s (- 1.19%) 5.49s 5.97s
Emit Time 2.75s (± 0.61%) 2.83s (± 3.46%) +0.08s (+ 2.88%) 2.70s 3.13s
Total Time 11.25s (± 0.14%) 11.29s (± 0.31%) +0.04s (+ 0.32%) 11.21s 11.36s
TFS - node (v8.9.0, x86)
Memory used 177,647k (± 0.02%) 177,611k (± 0.03%) -36k (- 0.02%) 177,443k 177,729k
Parse Time 1.62s (± 1.15%) 1.62s (± 0.80%) 0.00s ( 0.00%) 1.59s 1.64s
Bind Time 0.65s (± 1.02%) 0.66s (± 1.05%) +0.00s (+ 0.31%) 0.65s 0.68s
Check Time 4.89s (± 0.42%) 4.91s (± 0.92%) +0.02s (+ 0.35%) 4.83s 5.01s
Emit Time 2.83s (± 1.02%) 2.84s (± 1.10%) +0.02s (+ 0.67%) 2.76s 2.91s
Total Time 9.99s (± 0.46%) 10.03s (± 0.56%) +0.04s (+ 0.35%) 9.89s 10.17s
material-ui - node (v8.9.0, x86)
Memory used 279,883k (± 0.02%) 279,889k (± 0.01%) +7k (+ 0.00%) 279,830k 279,998k
Parse Time 2.55s (± 0.57%) 2.56s (± 0.84%) +0.01s (+ 0.39%) 2.51s 2.61s
Bind Time 0.73s (± 5.95%) 0.72s (± 5.67%) -0.01s (- 1.37%) 0.69s 0.88s
Check Time 16.66s (± 0.91%) 16.71s (± 0.68%) +0.06s (+ 0.34%) 16.37s 16.95s
Emit Time 0.00s (± 0.00%) 0.00s (± 0.00%) 0.00s ( NaN%) 0.00s 0.00s
Total Time 19.94s (± 0.74%) 19.99s (± 0.63%) +0.05s (+ 0.27%) 19.62s 20.24s
System
Machine Namets-ci-ubuntu
Platformlinux 4.4.0-197-generic
Architecturex64
Available Memory16 GB
Available Memory10 GB
CPUs4 × Intel(R) Core(TM) i7-4770 CPU @ 3.40GHz
Hosts
  • node (v10.16.3, x64)
  • node (v12.1.0, x64)
  • node (v8.9.0, x64)
  • node (v8.9.0, x86)
Scenarios
  • Angular - node (v10.16.3, x64)
  • Angular - node (v12.1.0, x64)
  • Angular - node (v8.9.0, x64)
  • Angular - node (v8.9.0, x86)
  • Compiler-Unions - node (v10.16.3, x64)
  • Compiler-Unions - node (v12.1.0, x64)
  • Compiler-Unions - node (v8.9.0, x64)
  • Compiler-Unions - node (v8.9.0, x86)
  • Monaco - node (v10.16.3, x64)
  • Monaco - node (v12.1.0, x64)
  • Monaco - node (v8.9.0, x64)
  • Monaco - node (v8.9.0, x86)
  • TFS - node (v10.16.3, x64)
  • TFS - node (v12.1.0, x64)
  • TFS - node (v8.9.0, x64)
  • TFS - node (v8.9.0, x86)
  • material-ui - node (v10.16.3, x64)
  • material-ui - node (v12.1.0, x64)
  • material-ui - node (v8.9.0, x64)
  • material-ui - node (v8.9.0, x86)
Benchmark Name Iterations
Current 41928 10
Baseline master 10

@jonhue
Copy link
Contributor Author

jonhue commented Dec 21, 2020

@andrewbranch I think we should probably alter the error message as well. Maybe something like The right-hand side of an 'in' expression must not extend a primitive type. Or do we want to keep it framed in a positive rather than a negative way?

@jonhue
Copy link
Contributor Author

jonhue commented Dec 22, 2020

Thank you for these test cases @andrewbranch! I'm not entirely sure about the behavior union4 yet, though.
Is there a reason why T extends object | "hello" should not exhibit the same behavior as T extends object | string?

Apart from the union4 case, all tests are green now. With the current implementation, the union4 case throws an error though.

@andrewbranch
Copy link
Member

I just used the string literal "hello" in that example to expand test coverage to other kinds of types, in sort of an arbitrary way. T extends object | "hello" should exhibit the same behavior as T extends object | string—both should be a valid RHS operand for in. It’s unfortunate that we can’t do better, but my view is that this one should be allowed because type guards will not work on T to narrow it to object, which is unquestionably a valid in operand. In other words, consider this example:

function f<T extends object | string>(p: T) {
  "" in p; // Not safe
  if (typeof p === "object") {
    "" in p; // Safe
  } else {
    "" in p; // Always an error
  }
}

We would prefer lines 2 and 6 to be an error, and 4 to be ok. But because we cannot refine the type of T, all three in expressions must have the same behavior in this function. So, we have to choose between all of them being an error or all of them being ok. Since it would be very annoying for line 4 to be an error when it’s clearly safe, and because the behavior today is that there are no errors, we should ensure that we don’t introduce new errors into this function with this PR.

@jonhue
Copy link
Contributor Author

jonhue commented Dec 28, 2020

@andrewbranch sorry for the late follow-up! Thank you for the additional example. I made the change so that only for unions and intersections we require all types to be non primitive (i.e. the type must be non primitive). For other types we only require that it may be non primitive.

@andrewbranch
Copy link
Member

@typescript-bot pack this

@typescript-bot
Copy link
Collaborator

typescript-bot commented Dec 28, 2020

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

@typescript-bot
Copy link
Collaborator

typescript-bot commented Dec 28, 2020

Hey @andrewbranch, 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/92138/artifacts?artifactName=tgz&fileId=BCCD3565559726AB186EEFDD383E53BB81588A4228FD5895A7EE828E9555FAE302&fileName=/typescript-4.2.0-insiders.20201228.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]".;

Copy link
Member

@andrewbranch andrewbranch left a comment

Choose a reason for hiding this comment

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

I think this looks right; let’s wait for some more team members to come back and try to break it!

@jonhue
Copy link
Contributor Author

jonhue commented Jan 11, 2021

@andrewbranch just out of curiosity, why is narrowing impossible on type parameters? Like in the example you gave above

function union4<T extends object | "hello">(thing: T) {
  "key" in thing; // Ok (because narrowing is impossible)
}

Is there a theoretical problem I'm not seeing that would make this unsound or is this a practical implementation issue or maybe even a conscious decision in favor of better performance? If it is a practical implementation issue, how hard do you think it would be to solve? In a quick search through the issues I wasn't able to find one that already tackles this in general, but I'm sure there must be one. I think #41333 is related. Thank you 🤗

@andrewbranch
Copy link
Member

#41333 is an instance of that, but I think #13995 may be the canonical one. Searching for "type parameter narrowing" turns up a lot of results that look relevant.

@andrewbranch
Copy link
Member

Actually #4742 might be the first and broadest

Copy link
Member

@sandersn sandersn left a comment

Choose a reason for hiding this comment

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

Also, I'd like to ship this before the 4.2 beta or after the 4.2 release, since it's possibly breaky still.

src/compiler/checker.ts Show resolved Hide resolved
src/compiler/checker.ts Show resolved Hide resolved
// If constraint is a union/intersection, ensure no types are primitive.
isTypeAssignableToKind(rightType, TypeFlags.UnionOrIntersection) && !allTypesAssignableToKind(rightTypeConstraint, TypeFlags.NonPrimitive | TypeFlags.InstantiableNonPrimitive) ||
// Otherwise, ensure that at least one type is not a primitive.
!maybeTypeOfKind(rightTypeConstraint, TypeFlags.NonPrimitive | TypeFlags.InstantiableNonPrimitive | TypeFlags.Object)
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 maybeTypeOfKind is correct here, but everything else uses assignability to NonPrimitive, and this isn't any kind of base case. I'd feel happier if the whole thing used assignability.

Copy link
Member

@andrewbranch andrewbranch Jan 11, 2021

Choose a reason for hiding this comment

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

Pasting from discussion in chat:

...applying your suggestion breaks a test case I designed—it adds new errors that are strictly more correct but more breaky, and a bigger divergence from existing behavior.

What maybeTypeOfKind allows for is this:

function union4<T extends object | "hello">(thing: T) {
  "key" in thing; // Ok (because narrowing is impossible)
}

I asserted that this should remain errorless, because we can't track the narrowing of thing if you type guarded that it was an object or not a string. Swapping maybeTypeOfKind for isTypeAssignableToKind makes it an error.

@andrewbranch
Copy link
Member

andrewbranch commented Jan 11, 2021

@jonhue I’m addressing @sandersn’s comments so we can get this merged before the 4.2 beta deadline (which was technically Friday 😅).

@andrewbranch
Copy link
Member

Oops, I can’t push to your branch, so I had to make a new one at #42288

andrewbranch added a commit that referenced this pull request Jan 12, 2021
…42288)

* 'in' should not operate on primitive types

* accept baselines of failing tests

* review

* update error message

* check if constraint of right type is assignable to a non primitive or instantiable non primitive

* do not throw errors where narrowing is impossible

* accept baselines

* fix test case failures

* Add more accurate comment discussion and document failing edge case in test

* Update baselines

Co-authored-by: Jonas Hübotter <[email protected]>
@andrewbranch
Copy link
Member

Merged in #42288. Thanks @jonhue!

Zzzen pushed a commit to Zzzen/TypeScript that referenced this pull request Jan 16, 2021
…branch) (microsoft#42288)

* 'in' should not operate on primitive types

* accept baselines of failing tests

* review

* update error message

* check if constraint of right type is assignable to a non primitive or instantiable non primitive

* do not throw errors where narrowing is impossible

* accept baselines

* fix test case failures

* Add more accurate comment discussion and document failing edge case in test

* Update baselines

Co-authored-by: Jonas Hübotter <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
For Milestone Bug PRs that fix a bug with a specific milestone
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

'in' should not operate on primitive types
6 participants