tc39 / source-map

Source map specification, RFCs and new proposals.
https://tc39.es/source-map/
Other
123 stars 16 forks source link

Scopes: Flexible scope "kind" on original scope prevents translation of function names in stack traces #133

Open szuend opened 1 day ago

szuend commented 1 day ago

Given the following authored code:

function foo() {  | (A) kind "function", name: "foo"
  if (...) {      |    | (B) kind "block", name: null
    x();          |    |
  }               |    |
}                 |

And the generated code:

function f() { | (R1)
  if (...) {   |    | (R2)
    x();       |    |
  }            |    |
}              |

The scopes proposal would put (A) as the definition of (R1) and (B) as the definition of (R2).

The call-site of x() would produce a stack frame with f 2:5. With that position we find the generated range (R2) and the corresponding original scope of (B). (B) doesn't have a name so we can't say what the original function name was.

The right thing to do, is walk the original scope chain outwards until we find an original scope that's "callable" (in this case (R1) and get the name from there, but "kind" is an arbitrary string, so we don't know how far to walk.

There are a couple of solutions how we can fix this:

  1. Revert the change that made kind into an arbitrary text and keep a pre-defined list of global, function and block. We can still add a kindLabel so generators can label original scopes more appropriately based on the source language.

  2. Leave "kind" as-is, but add a "isCallable"/"isFunction"/"showsUpInStackTrace" flag on original scopes.

  3. Require that anything callable has "kind" of 'function'. This seems very brittle to me and I'd prefer either a flag or a fixed original scope type.

Note that we can't just simply walk the original scope chain outwards until we find something with a name. Generators could emit scopes for classes, modules or namespaces with names that don't make sense to show in a stack trace.

jridgewell commented 9 hours ago

The generic kinds were meant to be defined by the language instead of by the spec. Eg, we left a Note: JavaScript implementations should use 'global', 'class', 'function', and 'block'., but C++ might choose different names.