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

Design Meeting Notes, 12/14/2018 #29033

Closed
DanielRosenwasser opened this issue Dec 14, 2018 · 0 comments
Closed

Design Meeting Notes, 12/14/2018 #29033

DanielRosenwasser opened this issue Dec 14, 2018 · 0 comments
Labels
Design Notes Notes from our design meetings

Comments

@DanielRosenwasser
Copy link
Member

Control Flow Analysis for Destructuring Assignments

#28792

let { x } = obj;

// *should* be equivalent to

let x = obj.x;

And this holds for any level of nesting.

let { x: { y } } = obj;

// *should* be equivalent to

let y = obj.x.y;

And the same for object pattern assignments

({ x } = obj);

// *should* be equivalent to

x = obj.x;
  • Today, we don't track these assignments as part of control flow analysis.
    • Trying to do so is actually pretty complex.
    • As a solution, we're considering a new "synthetic property access"

Unification

  • Consider

    function compose<A, B, C>(f1: (x: A) => B, f2: (x: B) => C): (x: A) => C { /*...*/ }
    function arrayToList<T>(x: T[]): List<T> { /*...*/ }
    function box<U>(x: U): { value: U } { /*...*/ }
    function first<W>(xs: List<W>): W { /*...*/ }
  • What if you wanted to write a function that box'd a list converted from an array? Ideally you could write the following:

    compose(arrayToList, box)

    and you'd get the type <T>(xs: T[]) => { value: List<T> }

    • Today the problem is that when our inference process sees no inferences for a type parameter, it infers its upper bound (which is implicitly {}).
    • Instead, what you really want to do is see that there are free type variables that are captured in the output, and attach them to the output type.
    • Starting off with this idea comes close. You get <T, U>(xs: T) => U, but of course, this doesn't propagate the original structures of inferences. Furthermore, T and U are unrelated. So what you want to do is unify the type variables during the first inference pass.
  • When you could do this is tough; you can't just replace the current inference process with unification. No telling what could break. But we can revisit that.

  • So saying "unification would do this" is fine, but how that happens is glossed over. There's some difficult cases.

  • A : T[]
    B : List<T>, SomeOtherList<W>
    C : W
    
  • Could say we only unify on named types.

    • What about object literal types?
    • It's a structural type system; y'can't backpedal on that.
  • Today we fix type parameters once they're requested in an anonymous function. How does this work with contextual typing?

    • Say it's there for single-signature types?

      • It's not about overloads.
    • Would we need to add type variables for anonymous functions?

    • Also, building up constraints could get gross:

      compose(arrayToList, x => x.get(0));
    • Could defer things.

    • The type might look gross for users. { get(): T } is not so bad, but imagine a more complex function body.

  • When you you're editing, what happens when the anonymous function comes first?

    • Hah.
    • Same downsides as today.
    • Functional users won't be happy with that experience.
      • "Daniel's not wrong"
        • [[First time anyone's ever said that]]
  • Seems like there's a lot of open questions.

Call signatures on union types

#7294
#29011

  • We erred on the safe side much of the time to say that signatures had to be identical.
  • In the last release, we expanded this to have signatures that totally subsumed other signatures available to callers.
  • When we unified JSX logic with call resolution logic, React users got broken because we were more permissive in React.
  • Okay, so we methods available a lot of the time when you have two union types; however, it doesn't work great for methods that take callbacks.
    • For example, if you have xs: string[] | number[], trying to call xs.forEach is possible, but lambda functions don't undergo contextual typing (one of our inference processes).
    • The reason why is that the contextual type is something like ((x: string) => void) & ((y: number) => void).
    • You'd think that would be fine and in xs.forEach(a => a), a would have the type string | number, but what instead happens is that ((x: string) => void) & ((y: number) => void) forms something that looks like an overload list, and lambdas aren't contextually typed by overloads.
  • Three solutions:
    • Change contextual typing to be contextually typed by overload lists.
    • Could come up with an underlying "intersection signature" (we have something similar for unions).
      • Means there's a difference between contextual typing and relationship checking.
    • Take the current fix (Allow calls on unions of dissimilar signatures #29011) as-is.
      • The forEach case is still broken, but at least we're better.
  • With the intersection signature strategy, what about an intersection where one type has no call signatures, and the other has many?
    • You'd have no "intersection signature", but a bunch of overloads.
    • One thing we didn't do here is try to come up with an intersection signature for multiple overloads; seems like a combinatorial explosion.
  • With the overload strategy, what about UX? What about huge overload lists like in the DOM?
  • Should we try to remove impossible never parameters from these "synthesized" signatures?
    • Seems like the wrong thing to focus on.
  • Out of time - seems like we're leaning towards overloads.
@DanielRosenwasser DanielRosenwasser added the Design Notes Notes from our design meetings label Dec 14, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Design Notes Notes from our design meetings
Projects
None yet
Development

No branches or pull requests

1 participant