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

Fixed union/intersection write types #56895

Closed

Conversation

Andarist
Copy link
Contributor

@Andarist Andarist commented Dec 29, 2023

@typescript-bot typescript-bot added the For Uncommitted Bug PR for untriaged, rejected, closed or missing bug label Dec 29, 2023
@@ -14674,7 +14674,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
else {
result.links.type = isUnion ? getUnionType(propTypes) : getIntersectionType(propTypes);
if (writeTypes) {
result.links.writeType = isUnion ? getUnionType(writeTypes) : getIntersectionType(writeTypes);
result.links.writeType = isUnion ? getIntersectionType(writeTypes) : getUnionType(writeTypes);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

after the original change has been merged it has been mentioned in the comments that likely this should work in the way I have adjusted it here but I don't see any open issue that would be the result of this discussion there

Copy link

@craigphicks craigphicks Dec 29, 2023

Choose a reason for hiding this comment

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

  1. Currently the getters and setter are displayed as plain readonly property (for getter) and plain property (for setter). See setter inferred from union has incorrect variance #56894 and Flow is improperly narrowing getter values #56899 which show the display. I think the displayed types should show getter and setter declarations so the user can understand the difference in behavior.
  2. What about the case where if (propTypes.length > 2){ ... } before this else clause? Isn't that branch handled later in different code which also has to be updated?
  3. A question: Apparently the writeTypes exists here for setters, because test results changed. But the tests results didn't change for plain types, so writeTypes does not exist for them, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

  1. if I understand you correctly - what is displayed depends on the location. In write locations, the write type is displayed and in read locations, you get the read type. To change this the TS team would have to receive a well-motivated feature request with many examples of how it would differ from the current behavior.
  2. Yes - you are right. I'll take a look at this.
  3. What do you consider a plain type here? Could you rephrase this question?

@craigphicks
Copy link

Although this is labelled as "fixes #56894" it does not change the behavior of the test case listed in that issue.

See here

@Andarist
Copy link
Contributor Author

Andarist commented Jan 1, 2024

I think that part of what you mention here is likely related to this and I'd treat this as another issue. If you prefer, I can remove the reference to your issue from this PR.

@craigphicks
Copy link

I think that part of what you mention here is likely related to this and I'd treat this as another issue. If you prefer, I can remove the reference to your issue from this PR.

Of course I prefer if this pull (appropriately modified) fixes #56894!!!
I posted #56922 which supersedes #56894 to highlight the runtime error risk.

@Andarist
Copy link
Contributor Author

Andarist commented Jan 2, 2024

I changed the referenced issue here as I don't want to fix the variance measurement for setters as part of this PR.

@andrewbranch
Copy link
Member

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

@typescript-bot
Copy link
Collaborator

typescript-bot commented Jan 2, 2024

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

Update: The results are in!

@typescript-bot
Copy link
Collaborator

typescript-bot commented Jan 2, 2024

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

Update: The results are in!

@typescript-bot
Copy link
Collaborator

typescript-bot commented Jan 2, 2024

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

Update: The results are in!

@andrewbranch
Copy link
Member

@typescript-bot pack this

@typescript-bot
Copy link
Collaborator

typescript-bot commented Jan 2, 2024

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

@typescript-bot
Copy link
Collaborator

typescript-bot commented Jan 2, 2024

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/159197/artifacts?artifactName=tgz&fileId=4AC9367E469335C2C0558E744EF14213E5A37BE0E1FA3559595B0080FA27F1B802&fileName=/typescript-5.4.0-insiders.20240102.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

@andrewbranch Here are the results of running the user test suite comparing main and refs/pull/56895/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

@andrewbranch
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,441k (± 0.01%) 295,451k (± 0.01%) ~ 295,419k 295,499k p=0.689 n=6
Parse Time 2.66s (± 0.51%) 2.65s (± 0.31%) ~ 2.63s 2.65s p=0.180 n=6
Bind Time 0.82s (± 0.63%) 0.82s (± 0.00%) ~ 0.82s 0.82s p=0.174 n=6
Check Time 8.16s (± 0.43%) 8.16s (± 0.42%) ~ 8.12s 8.21s p=1.000 n=6
Emit Time 7.11s (± 0.22%) 7.09s (± 0.15%) ~ 7.08s 7.11s p=0.071 n=6
Total Time 18.75s (± 0.25%) 18.72s (± 0.25%) ~ 18.67s 18.79s p=0.467 n=6
Compiler-Unions - node (v18.15.0, x64)
Memory used 191,484k (± 0.03%) 191,467k (± 0.02%) ~ 191,418k 191,532k p=0.378 n=6
Parse Time 1.35s (± 0.86%) 1.34s (± 1.13%) ~ 1.33s 1.37s p=0.363 n=6
Bind Time 0.72s (± 0.00%) 0.72s (± 0.00%) ~ 0.72s 0.72s p=1.000 n=6
Check Time 9.24s (± 0.32%) 9.26s (± 0.31%) ~ 9.24s 9.32s p=0.258 n=6
Emit Time 2.61s (± 0.51%) 2.62s (± 0.95%) ~ 2.59s 2.66s p=0.566 n=6
Total Time 13.92s (± 0.28%) 13.95s (± 0.28%) ~ 13.90s 14.00s p=0.261 n=6
Monaco - node (v18.15.0, x64)
Memory used 347,385k (± 0.00%) 347,385k (± 0.01%) ~ 347,366k 347,419k p=0.810 n=6
Parse Time 2.46s (± 0.31%) 2.46s (± 0.22%) ~ 2.45s 2.46s p=0.137 n=6
Bind Time 0.92s (± 0.59%) 0.93s (± 0.00%) ~ 0.93s 0.93s p=0.071 n=6
Check Time 6.86s (± 0.40%) 6.88s (± 0.20%) ~ 6.86s 6.90s p=0.625 n=6
Emit Time 4.06s (± 0.36%) 4.04s (± 0.40%) ~ 4.01s 4.05s p=0.067 n=6
Total Time 14.31s (± 0.14%) 14.29s (± 0.15%) ~ 14.25s 14.31s p=0.285 n=6
TFS - node (v18.15.0, x64)
Memory used 302,719k (± 0.00%) 302,712k (± 0.01%) ~ 302,690k 302,739k p=0.421 n=6
Parse Time 1.99s (± 1.04%) 1.98s (± 1.22%) ~ 1.95s 2.02s p=0.935 n=6
Bind Time 1.00s (± 0.52%) 1.01s (± 1.02%) ~ 0.99s 1.02s p=0.077 n=6
Check Time 6.30s (± 0.57%) 6.30s (± 0.28%) ~ 6.28s 6.33s p=0.683 n=6
Emit Time 3.59s (± 0.38%) 3.57s (± 0.46%) ~ 3.56s 3.60s p=0.222 n=6
Total Time 12.88s (± 0.39%) 12.87s (± 0.31%) ~ 12.82s 12.93s p=0.808 n=6
material-ui - node (v18.15.0, x64)
Memory used 506,830k (± 0.01%) 506,824k (± 0.00%) ~ 506,805k 506,848k p=1.000 n=6
Parse Time 2.58s (± 0.49%) 2.59s (± 0.67%) ~ 2.57s 2.62s p=0.187 n=6
Bind Time 0.99s (± 1.05%) 0.99s (± 1.11%) ~ 0.98s 1.01s p=0.401 n=6
Check Time 16.93s (± 0.30%) 16.89s (± 0.20%) ~ 16.84s 16.93s p=0.147 n=6
Emit Time 0.00s (± 0.00%) 0.00s (± 0.00%) ~ 0.00s 0.00s p=1.000 n=6
Total Time 20.51s (± 0.27%) 20.47s (± 0.14%) ~ 20.43s 20.52s p=0.296 n=6
xstate - node (v18.15.0, x64)
Memory used 512,864k (± 0.01%) 512,870k (± 0.01%) ~ 512,782k 512,915k p=0.689 n=6
Parse Time 3.28s (± 0.26%) 3.27s (± 0.27%) ~ 3.26s 3.28s p=0.437 n=6
Bind Time 1.54s (± 0.49%) 1.54s (± 0.26%) ~ 1.54s 1.55s p=1.000 n=6
Check Time 2.81s (± 0.45%) 2.82s (± 0.43%) ~ 2.81s 2.84s p=0.167 n=6
Emit Time 0.07s (± 0.00%) 0.07s (± 0.00%) ~ 0.07s 0.07s p=1.000 n=6
Total Time 7.70s (± 0.26%) 7.71s (± 0.16%) ~ 7.69s 7.72s p=0.511 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,356ms (± 0.49%) 2,347ms (± 1.03%) ~ 2,314ms 2,379ms p=0.521 n=6
Req 2 - geterr 5,429ms (± 1.08%) 5,478ms (± 1.69%) ~ 5,371ms 5,580ms p=0.575 n=6
Req 3 - references 325ms (± 0.95%) 326ms (± 0.90%) ~ 322ms 330ms p=0.745 n=6
Req 4 - navto 278ms (± 1.03%) 276ms (± 1.26%) ~ 273ms 281ms p=0.245 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 89ms (± 5.36%) 89ms (± 5.34%) ~ 83ms 93ms p=1.000 n=6
CompilerTSServer - node (v18.15.0, x64)
Req 1 - updateOpen 2,487ms (± 0.96%) 2,488ms (± 0.88%) ~ 2,471ms 2,530ms p=0.297 n=6
Req 2 - geterr 4,093ms (± 0.19%) 4,137ms (± 1.71%) ~ 4,080ms 4,236ms p=0.575 n=6
Req 3 - references 344ms (± 1.05%) 342ms (± 1.46%) ~ 337ms 348ms p=0.746 n=6
Req 4 - navto 285ms (± 0.22%) 283ms (± 0.29%) -2ms (- 0.58%) 282ms 284ms p=0.008 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 89ms (± 0.46%) 86ms (± 6.80%) ~ 78ms 90ms p=0.849 n=6
xstateTSServer - node (v18.15.0, x64)
Req 1 - updateOpen 2,605ms (± 0.65%) 2,609ms (± 0.53%) ~ 2,583ms 2,621ms p=0.298 n=6
Req 2 - geterr 1,724ms (± 2.30%) 1,705ms (± 2.29%) ~ 1,660ms 1,754ms p=0.470 n=6
Req 3 - references 112ms (± 9.97%) 116ms (± 8.82%) ~ 102ms 123ms p=0.366 n=6
Req 4 - navto 365ms (± 0.51%) 364ms (± 0.68%) ~ 359ms 366ms p=0.554 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 310ms (± 1.90%) 306ms (± 2.03%) ~ 298ms 314ms p=0.261 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 153.28ms (± 0.25%) 153.14ms (± 0.21%) -0.13ms (- 0.09%) 151.91ms 157.62ms p=0.000 n=600
tsserver-startup - node (v18.15.0, x64)
Execution time 228.36ms (± 0.17%) 228.16ms (± 0.14%) -0.21ms (- 0.09%) 226.53ms 231.40ms p=0.000 n=600
tsserverlibrary-startup - node (v18.15.0, x64)
Execution time 230.02ms (± 0.19%) 230.09ms (± 0.18%) ~ 228.30ms 233.13ms p=0.067 n=600
typescript-startup - node (v18.15.0, x64)
Execution time 229.91ms (± 0.19%) 229.97ms (± 0.19%) ~ 228.14ms 235.80ms p=0.186 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

@gabritto
Copy link
Member

gabritto commented Jan 2, 2024

As pointed out already, we should either not close #56922 with this PR or, preferably, re-open #56894 to track the setter variance computation issue.

@Andarist
Copy link
Contributor Author

Andarist commented Jan 2, 2024

I think the currently linked issue can be closed with this. From my PoV, its main focus is on those unsound writes that are fixed here. I agree that the other issue could be reopened to track the variance computation issue.

@typescript-bot
Copy link
Collaborator

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

Everything looks good!

@andrewbranch
Copy link
Member

I'm surprised I can't find discussion on this, but I think we discussed this when we added the divergent accessor type feature and decided to make the implementation consistent with the (obviously incorrect) way that normal properties work. This PR does not make this an error:

class One {
    x!: string
}
class Two {
    x!: number
}
declare let u1: One | Two;
u1.x = "";

I would like to see this fixed everywhere, but that's of course a much bigger and more disruptive change, and I'm not sure if it makes sense to fix one without the other. Even more confusing, the logic changed here doesn't even kick in unless the property has a getter with a different type. This is still not an error:

declare class OneAccessor {
    set x(value: string);
}
declare class TwoAccessor {
    set x(value: number);
}
declare let u2: OneAccessor | TwoAccessor;
u2.x = "";

And it's still not an error when adding getters of the same type. But once one of the getters—theoretically irrelevant to this assignment—diverges from its setter, suddenly the assignment is an error? No, unfortunately, I think this is wrong on purpose.

@Andarist
Copy link
Contributor Author

Andarist commented Jan 2, 2024

I would like to see this fixed everywhere, but that's of course a much bigger and more disruptive change, and I'm not sure if it makes sense to fix one without the other.

To confirm - is this something that you want to get fixed? I could certainly try to do this, I'm just looking for a soft confirmation that fixing this is even on the table. As you have said, it could potentially be a big and disruptive change - and I know that sometimes the team errs on the side of backwards compatibility.

@andrewbranch
Copy link
Member

I'm not sure when it was last discussed, but my impression was it's not on the table. I think the problem is that it's too slippery of a slope down to the realization that all non-readonly properties should be strictly invariant, which would be an unacceptably large break without a flag, and possibly too onerous even with a flag.

let obj: { x: string } | { x: number };
obj.x = ""; // Error, right?
let obj2: { x: unknown } = obj; // ...Uh oh
obj2.x = ""; // Must be ok, so previous line must be error

#14150
#18770

@Andarist Andarist closed this Jan 2, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
For Uncommitted Bug PR for untriaged, rejected, closed or missing bug
Projects
None yet
Development

Successfully merging this pull request may close these issues.

treating setters as properties rather than functions can be unsound
5 participants