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, 7/12/2024 #59362

Open
DanielRosenwasser opened this issue Jul 19, 2024 · 1 comment
Open

Design Meeting Notes, 7/12/2024 #59362

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

Comments

@DanielRosenwasser
Copy link
Member

Making Type Error Elaboration More Consistent

#58859

  • Problem: you may get a different error elaboration in different locations depending on the order in which a program is checked.
    • There are various reasons for this, with the class of differences we're concerned about here, but we try to avoid reporting the full context if you've already seen it.
  • The main reason we're focusing on this is region-based diagnostics. If you first check statements in the middle of the file, it is weird to get a different level of error detail than top-down checking.
  • In this PR, every time we report a type error, we will now provide the full elaboration.

Deferred Parameters and Control Flow Analysis for Function Expression Arguments

#58729

  • Feel it is a valuable fix for a long-standing problem.

  • Core idea is to assume that callback function expressions are possibly called, and to factor that into the control flow analysis of variables used afterwards.

  • Means that in cases like

    let x: number | undefined;
    x = 42;
    someArray.forEach(() => { x = undefined; });
    x++; // Should be an error. Was not previously, is an error with this PR.

    now correctly fail to type-check.

  • To opt out, the idea is to introduce a deferred modifier; but there's a compatibility problem with all the tools in the ecosystem understanding that. Declaration files will need to introduce it and split between typesVersions, existing code may need an annotation even in .ts files.

    • PR also has support for /** @deferred */ JSDoc comment that is understood in .ts files - not just .js files.
  • Also a question of a new parameter modifier being possibly in conflict with JavaScript.

    • We don't see one, but it might be worth reaching out to the committee to better understand concerns.
  • What's the relationship between a deferred callback and await?

    • It doesn't really factor in; we don't analyze deferred callbacks other than at the use-site.
  • How does declaration emit work for the JSDoc tag?

    • What you write is what you get.
  • What happens when a library is not upgraded to use deferred?

    • You can just use a type assertion to the expected type to opt out.

    • Alternatively, and maybe more preferred, is to write a function that takes a deferred callback and returns it.

      function deferred<F extends (...args: never[]) => unknown>(deferred callback: F): F {
          return callback;
      }
  • We want to make sure that we're not missing anything. Will do the work to get Node.js and lib.d.ts/DOM libraries to have deferred.

type DataOrNull<T> = {
    data: T | null;
};

declare function check(s: DataOrNull<string>): void;

declare let foo: DataOrNull<string | null>;
check(foo); // Error?
  • We "smartly" infer that T is covariant (please disregard the soundness aspect here).

    • When we ask if DataOrNull<string | null> is assignable to DataOrNull<string>, we try to just ask "is string | null assignable to string?" and answer "no".
  • One idea: give people a new opt-out for variance calculation?

    type DataOrNull<unmeasurable T> = {
        data: T | null;
    };
  • "Unmeasurable" is the concept we use internally to say "this type parameter must always be checked with respect to the structure of the containing type".

  • What do we name this?

    type DataOrNull<sus T> = {
        data: T | null;
    };
  • structural?

  • linear?

  • inconsistent?

  • nonvariant

  • Could we infer this better?

    • The pattern is common, and if we don't infer some variance in these scenarios, things are likely to get quite a bit slower.
  • Isn't a similar problem going to come up with libraries prioritizing correctness?

    • Unmeasurable variance is pretty infectious with type parameters. A type reference that takes a type variable for an unreliable type parameter makes the type variable also unreliable with respect to its containing type.
  • Could view this as "unreliable" - another internal view of type parameters, where they might have a variance, but uses the structural fallback.

  • What about this on the use-site?

    declare let foo: DataOrNull<structural string>;
    • Hard to think about what that means/explain to developers.
  • There are hacks to induce unreliable variance. @RyanCavanaugh will post this.

@DanielRosenwasser DanielRosenwasser added the Design Notes Notes from our design meetings label Jul 19, 2024
@RyanCavanaugh
Copy link
Member

Ref #59049, #9998

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