Skip to content

Design Meeting Notes, 10/11/2024 #60286

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

Open
DanielRosenwasser opened this issue Oct 18, 2024 · 1 comment
Open

Design Meeting Notes, 10/11/2024 #60286

DanielRosenwasser opened this issue Oct 18, 2024 · 1 comment
Labels
Design Notes Notes from our design meetings

Comments

@DanielRosenwasser
Copy link
Member

Conditional Type Narrowing

#56941

  • Today, we check an expression like

    arg === 1 ? "someString" : 37

    by getting the type of both branches and unioning them - and we can't make a determination about how either branch corresponds to the condition.

  • In the experimental PR, each branch is checked the expected type.

    • This is a breaking change, but it catches some desirable breaks.

    • For example:

      // Currently the expression's type is `any` and we check that against `number`,
      // but checked individually, the `string` is correctly caught.
      let x: number = arg === 1 ? "someString" : getAnAny() as any;
      
  • Breaks?

    • Most are true bugs
    • Good chunk are moves in error positions (breaks ts-expect-error)
    • Some unlikely to be real bugs.
  • The motivation was conditional type narrowing - if you think of first principals, you could consider that the conditional expression creates a conditional type.

    • Not too hard to do, but
      • Need to be able to "crack into" each branch of the conditional type for the return statement case as well.

      • You also might not get the "right" conditional type. For example

        function f(x: T): T extends string ? string : number {
            return x === undefined ? someString : someNumber;
        }
        
        • Do you end up synthesizing T extends string ? ... : ... or do you create T extends undefined ? ... : ...?
      • Also, error messages won't be quite as good.

  • Out of time

Slim AST Experiments with Shared Structs in the Compiler

#59992

  • Partially inspired by Make AST nodes monomorphic. #59190

  • Uses flagged functionality for SharedStructs via API (no syntax for shared structs yet).

  • Idea: every Node is has single a fixed layout.

    • Also experimenting with a version that uses shared structs.
  • Separately: a different experiment Uses a "slim AST" which creates a facade to the real AST for API compat.

  • Experimental parser that uses this.

  • You get a speed-up similar to Make AST nodes monomorphic. #59190, though it's at the expense of more memory.

    • Much more (why?)
  • If you use shared structs as the backing store for the slim AST, you lose some speed (we anticipate more optimizations with collaboration from V8), but possibly win back some memory and are able to run across multiple threads and you get a net perf win.

    Node Type Allocation Source Time (seconds)
    Current AST Plain objects 1.76
    slim-ast plain objects 1.562
    slim-ast shared structs 2.013
    slim-ast shared structs across 8 workers 1.082
@DanielRosenwasser DanielRosenwasser added the Design Notes Notes from our design meetings label Oct 18, 2024
@gabritto
Copy link
Member

Clarification about conditional expression checking: the change in my PR is only for conditional expressions in a return statement, so this will remain the same:

let x: number = arg === 1 ? "someString" : getAnAny() as any; // no error

This will now error:

function fun(arg: number): number {
    return arg === 1 ? "someString" : getAnAny() as any; // error in PR
}

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

2 participants