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, 4/1/2022 #48685

Closed
DanielRosenwasser opened this issue Apr 13, 2022 · 0 comments
Closed

Design Meeting Notes, 4/1/2022 #48685

DanielRosenwasser opened this issue Apr 13, 2022 · 0 comments
Labels
Design Notes Notes from our design meetings

Comments

@DanielRosenwasser
Copy link
Member

Improved Inference on Context Sensitive Expressions

#47599

  • Seen examples of contextually sensitive functions that don't correctly receive contextual types because they're put in object literals.
    • Typically due to ordering issues.
declare function callIt<T>(obj: {
    produce: (n: number) => T,
    consume: (x: T) => void
}): void;

// Works
callIt({
    produce: () => 0,
    consume: n => n.toFixed()
});

// Fails for no obvious reason
callIt({
    produce: _a => 0,
    consume: n => n.toFixed()
});

// Fails for no obvious reason
callIt({
    produce() {
        return 0;
    },
    consume: n => n.toFixed()
});
  • Why do these fail?

    • _a => 0 is contextually sensitive due to _a not having a type annotation.
    • produce() is contextually sensitive because it has an implicit this parameter which is contextually sensitive.
  • Functions are context-sensitive when there's a parameter for which there's no type annotation.

    • That also means almost all object methods are contextually sensitive because none of them have an explicitly annotated this.
  • Today, we infer from non-sensitive expressions in a first pass - so () => 0 gives a good inference to start in case a contextually-sensitive function needs the inferred type. Then we give contextually sensitive functions the right type in a second pass of inference.

    • Aside: that's really the point of determining whether functions are contextually sensitive - to know whether we should look for other candidates for inference first.
  • Part of this is because we ask for the overall type of the object which immediately fixes the type of T unnecessarily.

    • If you split properties into their own objects, you wouldn't need to ask for the type of the entire object.

      // Works!
      declare function callIt<T>(
          a: { produce: (n: number) => T },
          b: { consume: (x: T) => void },
      ): void;
      
      callIt(
          { produce: _a => 0 },
          { consume: n => n.toFixed() },
      );
  • So what we do now is that when we see a contextually sensitive function in an object, we try to ask specifically for the contextual type of the respective member of an object without asking for the contextual type of the containing object literal.

    • This gives a nicer left-to-right flow of types between properties that seems more in-line with contextual typing for arguments.

Towards Non-Fungible Types

#48513

@DanielRosenwasser DanielRosenwasser added the Design Notes Notes from our design meetings label Apr 13, 2022
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