microsoft / TypeScript

TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
https://www.typescriptlang.org
Apache License 2.0
100.28k stars 12.39k forks source link

Soft Asserts and Contained Crashes #47328

Open DanielRosenwasser opened 2 years ago

DanielRosenwasser commented 2 years ago

Much of the time, assertions are used to check our own assumptions - however, many of those assumptions have recoverable behaviors if they cease to be true.

As a simple example, let's consider document highlights. TypeScript provides document highlights on any of the switch, case or break keywords of a switch/case statement.

[|switch|] (foo) {
  [|case|] 0:
    foo()
  [|case|] 1:
    bar();
    break;
}

Now imagine that JavaScript ends up getting a fallthrough keyword. If I recall correctly, document highlights throws an exception and provides no results if nobody remembers update document highlights for the fallthrough keyword (and in fact, this has happened with other features).

Alternatively, document highlights could somehow log that an expectation was violated and find a more general behavior in the meantime like providing highlights for all fallthrough keywords in the current file. This would ensure that some results can be returned instead of no results.

Document highlights are subtle though. What about a more impactful feature that you really feel a failure around? For a different example, let's discuss completions.

A failure in auto-completion is very noticeable. Obviously using the same idea from above, an assertion failure in the language service shouldn't tank an entire completions request.

Going even further though, we also have a set of failure conditions that may be partially recoverable. This occasionally comes up from failures in our auto-import provider. Completions use a scoped program instance to provide auto-import completions. In spirit, a failure in auto-imports shouldn't ruin local completions, but we sure would like to know about when a user isn't getting auto-imports!

From what @andrewbranch has raised, because this entire subsystem of completions is silo'd off, it can be wrapped in a try/catch and logged in a similar manner.

This class of "soft" assertions and failures can be provided as "hard" errors on the command line, and turned into events for language services. An insiders version of Visual Studio Code could prompt a dialog to file a bug when it encounters these soft assertions, and stable versions of VS/VS Code could surface them through telemetry (similar to what it does for regular crashes today).

fatcerberus commented 2 years ago

Now imagine that JavaScript ends up getting a fallthrough keyword. If I recall correctly, document highlights throws an exception and provides no results if nobody remembers update document highlights for the fallthrough keyword (and in fact, this has happened with other features).

I don't understand why this would cause an exception (but I'm admittedly not familiar with the compiler internals...) The worst I can imagine happening in this scenario is that it fails to highlight the fallthrough keyword. Where would this exception be coming from, assuming the keyword is otherwise parsed correctly by the compiler?

DanielRosenwasser commented 2 years ago

My example was slightly off - but it was based on

https://github.com/microsoft/TypeScript/blob/e10c912bf6d6424783baa55511b4caeb52ee14c5/src/services/documentHighlights.ts#L252

Here's two PRs in the last 2 years that had to handle this: