Skip to content

combinatorial explosion of recursive unions definitions. #18754

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

Closed
sledorze opened this issue Sep 25, 2017 · 16 comments
Closed

combinatorial explosion of recursive unions definitions. #18754

sledorze opened this issue Sep 25, 2017 · 16 comments
Labels
Fixed A PR has been merged for this issue

Comments

@sledorze
Copy link

sledorze commented Sep 25, 2017

TypeScript Version: 2.5.2

Code

type A = { tag: 'a', pa: ALL}
type B = { tag: 'b', pb: ALL}
type C = { tag: 'c', pc: ALL}
type D = { tag: 'd', pd: ALL}
type E = { tag: 'e', pe: ALL}
type ALL = A | B | C | D | E

Expected behavior:

When hovering on pa ... pe members, we see a few types, ideally just 'ALL'.

Actual behavior:

When hovering on pa ... pe members, we see an explosion of types.

@DanielRosenwasser
Copy link
Member

I'm not seeing this in the playground or the nightlies.

@DanielRosenwasser DanielRosenwasser added the Needs More Info The issue still hasn't been fully clarified label Sep 25, 2017
@sledorze
Copy link
Author

sledorze commented Sep 25, 2017

@DanielRosenwasser I've seen that in VSCode, can you try in it?
( in the playground that looks like what I would expect )

I have two concerns:

  • It lags terribly when editing.
  • I'm afraid this pattern could lead to some OOM when compiling.
    for information, in VSCode, the class version does not exhibit the issue.
class CA { tag: 'a'; pa: CALL }
class CB { tag: 'b'; pb: CALL }
class CC { tag: 'c'; pc: CALL }
class CD { tag: 'd'; pc: CALL }
class CE { tag: 'e'; pc: CALL }
type CALL = CA | CB | CC | CD | CE

@mhegazy
Copy link
Contributor

mhegazy commented Sep 26, 2017

Can you share some more context. like a bigger code sample?

@sledorze
Copy link
Author

sledorze commented Sep 26, 2017

@mhegazy @DanielRosenwasser oh that's strange!

I found out it happens when I do an import like this at the top of the file:

import * as t from 'io-ts' 

type A = { tag: 'a', pa: ALL}
type B = { tag: 'b', pb: ALL}
type C = { tag: 'c', pc: ALL}
type D = { tag: 'd', pd: ALL}
type E = { tag: 'e', pe: ALL}
type ALL = A | B | C | D | E

Here's a repo exhibiting the issue, this one with latest TS 2.6.0-dev.20170926 ( happens on both that version and 2.5.2, I've not checked others ) :
https://github.com/sledorze/tsInferenceIssue

@sledorze
Copy link
Author

sledorze commented Sep 26, 2017

Actually, I'm even not requiring io-ts, I've updated the repo with a version that just tries to import an empty module.

emptymodule.ts

export { }

test.ts

import * as t from './emptymodule'

type ZA = { tag: 'a', pa: ALL }
type ZB = { tag: 'b', pb: ALL }
type ZC = { tag: 'c', pc: ALL }
type ZD = { tag: 'd', pc: ALL }
type ZE = { tag: 'e', pc: ALL }
type ALL = ZA | ZB | ZC | ZD | ZE

screen shot 2017-09-26 at 09 07 37

@sledorze
Copy link
Author

@sledorze
Copy link
Author

Also this one exhibit the error

type ZA = { tag: 'a', pa: ALL }
type ZB = { tag: 'b', pb: ALL }
type ZC = { tag: 'c', pc: ALL }
type ZD = { tag: 'd', pc: ALL }
type ZE = { tag: 'e', pc: ALL }
type ALL = ZA | ZB | ZC | ZD | ZE
export {  ALL }

whereas this one not

type ZA = { tag: 'a', pa: ALL }
type ZB = { tag: 'b', pb: ALL }
type ZC = { tag: 'c', pc: ALL }
type ZD = { tag: 'd', pc: ALL }
type ZE = { tag: 'e', pc: ALL }
export type ALL = ZA | ZB | ZC | ZD | ZE

So there's a kind of 'workaround' so far..

@sledorze
Copy link
Author

@mhegazy @DanielRosenwasser enough information to emit a judgment if either this is a bug or a by design limitation?

@mhegazy
Copy link
Contributor

mhegazy commented Oct 11, 2017

Automatically closing this issue for housekeeping purposes. The issue labels indicate that it is unactionable at the moment or has already been addressed.

@DanielRosenwasser
Copy link
Member

This is definitely undesirable behavior, but can you give us more context on how you're running into this in the first place? Specifically, what is the motivating use-case?

@DanielRosenwasser DanielRosenwasser removed the Needs More Info The issue still hasn't been fully clarified label Oct 12, 2017
@mhegazy
Copy link
Contributor

mhegazy commented Oct 12, 2017

I am unable to get a repro for the issue described in this thread. @sledorze can you share a self-contained repro for the issue.

@sledorze
Copy link
Author

@mhegazy here's a playground link that reproduce the issue:
https://www.typescriptlang.org/play/#src=export%20%7B%7D%0D%0A%0D%0Atype%20A%20%3D%20%7B%20tag%3A%20'a'%2C%20pa%3A%20ALL%20%7D%0D%0Atype%20B%20%3D%20%7B%20tag%3A%20'b'%2C%20pb%3A%20ALL%7D%0D%0Atype%20C%20%3D%20%7B%20tag%3A%20'c'%2C%20pc%3A%20ALL%7D%0D%0Atype%20D%20%3D%20%7B%20tag%3A%20'd'%2C%20pd%3A%20ALL%7D%0D%0Atype%20E%20%3D%20%7B%20tag%3A%20'e'%2C%20pe%3A%20ALL%7D%0D%0Atype%20ALL%20%3D%20A%20%7C%20B%20%7C%20C%20%7C%20D%20%7C%20E%0D%0A

just hover over the ALL definition to see the types..

@DanielRosenwasser the use case is implementing a recursive algebra (a Query AST); the obvious work around is using interfaces instead of types but I found that pretty counter intuitive and unhandy that adding an export changes the type inference.

@gcnew
Copy link
Contributor

gcnew commented Oct 12, 2017

I've been experiencing the same problem. I've converted all of minijs' AST types to interfaces, because IntelliSense was stopping to show up and after a considerable wait, tsserver was crashing.

Here's a playground link demonstrating the problem when using type instead of interface (types copied from minijs). Hover over Expr or any other complex type. Note: if you remove export {} aliases are no longer expanded and the issue does not surface.

@DanielRosenwasser
Copy link
Member

I've converted all of minijs' AST types to interfaces

I think that this has been the guidance we've had for users for a while.

Still, I know this is unexpected. @ahejlsberg had an explanation of why we reuse type alias names in global contexts as opposed to within a module.

@sledorze
Copy link
Author

There's a lot of difference going on now when switching from types to interfaces, I'm referring specifically to variance and type safety.
It is highly desirable not to have to choose between recursivity and type safety (co/contra-variance).

@mhegazy
Copy link
Contributor

mhegazy commented Jul 18, 2018

Should be fixed in latest.

@mhegazy mhegazy closed this as completed Jul 18, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Fixed A PR has been merged for this issue
Projects
None yet
Development

No branches or pull requests

4 participants