ecma262 icon indicating copy to clipboard operation
ecma262 copied to clipboard

Normative: Allow toString of a built-in function to output a computed property name

Open gibson042 opened this issue 3 years ago • 10 comments
trafficstars

e.g., as output by XS:

$ eshost -se 'Proxy.revocable({}, {}).revoke.toString()'
#### ChakraCore, SpiderMonkey
function() {
    [native code]
}

#### engine262, GraalJS, Hermes, V8
function () { [native code] }

#### JavaScriptCore
function () {
    [native code]
}

#### Moddable XS
function [""] (){[native code]}

gibson042 avatar Mar 16 '22 20:03 gibson042

Does anyone but xs do this? This doesn't really seem to match the intention of toString reform, altho "it can't parse" certainly means it validates the letter.

It seems like perhaps a simpler approach is to add test262 tests to prohibit what xs is doing, assuming they're willing to change their behavior?

ljharb avatar Mar 16 '22 21:03 ljharb

That's possible, but note that every major engine and most minor ones also output similar strings in certain scenarios (albeit not necessarily for built-in functions):

$ eshost -se '(function(){
  const sym1 = Symbol("foo"), sym2 = Symbol("bar"), obj = { [sym1](){}, get [sym2](){} };
  const m1 = obj[sym1], m2 = Object.getOwnPropertyDescriptor(obj, sym2).get;
  return [m1, m2, m1.bind(), m2.bind()].map(
    fn => `${fn} # => ${JSON.stringify(fn.name)}`.replace(/\s*([(){}])\s*/g, " $1 ").replace(/\s+/g, " ")
  ).join("\n");
})()'
#### ChakraCore

TypeError: No implicit conversion of Symbol to String

#### engine262, SpiderMonkey, V8
[sym1] ( ) { } # => "[foo]"
get [sym2] ( ) { } # => "get [bar]"
function ( ) { [native code] } # => "bound [foo]"
function ( ) { [native code] } # => "bound get [bar]"

#### JavaScriptCore
function ( ) { } # => "[foo]"
function ( ) { } # => "get [bar]"
function [foo] ( ) { [native code] } # => "bound [foo]"
function get [bar] ( ) { [native code] } # => "bound get [bar]"

#### Moddable XS
function ["[foo]"] ( ) { [native code] } # => "[foo]"
function ["get [bar]"] ( ) { [native code] } # => "get [bar]"
function ["bound [foo]"] ( ) { [native code] } # => "bound [foo]"
function ["bound get [bar]"] ( ) { [native code] } # => "bound get [bar]"

gibson042 avatar Mar 16 '22 21:03 gibson042

The title of this PR is misleading. Computed property names are already allowed in Function.prototype.toString output. The grammar changes here are simply a refactoring. Can you update the title to describe the actual normative requirement change?

michaelficarra avatar Mar 17 '22 15:03 michaelficarra

The title of this PR is misleading. Computed property names are already allowed in Function.prototype.toString output. The grammar changes here are simply a refactoring. Can you update the title to describe the actual normative requirement change?

The current output for built-in functions (with a String-valued [[InitialName]]) is constrained by "the portion of the returned String that would be matched by |NativeFunctionAccessor?| |PropertyName| must be the value of func.[[InitialName]]" (emphasis mine), which does not permit a computed property name because String contents like [""] do not match the value of "" (even though they are grammatically permitted by |NativeFunction|).

So I believe that the title already describes this normative change, although I'm open to alternative suggestions.

gibson042 avatar Mar 18 '22 02:03 gibson042

I don't like the strategy of parsing and evaluating the property name here, especially if all of PropertyName is allowed, which potentially includes arbitrary expressions. If we're introducing a new AO anyway, just change NativeFunctionName to permit a subset of the PropertyName grammar and introduce an SDO that extracts the name from that. If it's not clear what I mean, we can get on a call or you can join the weekly editor call.

michaelficarra avatar Jul 12 '22 02:07 michaelficarra

@gibson042 separate from the mechanism of doing the change, can you elaborate on why this is desirable?

ljharb avatar Jul 13 '22 22:07 ljharb

separate from the mechanism of doing the change, can you elaborate on why this is desirable?

There are editorial aspects which are important to make the current text actually coherent (which I will split out into a separate PR: #2828), and normative aspects relating to consistency of valid output from Function.prototype.toString(callableWithoutASourceTextSlot)... right now the output for a built-in function is much more constrained than the output for other such callables such as proxies and/or bound versions of accessor and/or symbol-named functions (cf. https://github.com/tc39/ecma262/pull/2695#issuecomment-1069648775 ) in that the [[InitialName]] requirement (seems to) preclude a computed name, but not so constrained that it is actually deterministic (in that the presence and form of whitespace is unspecified).

But if there is implementer appetite for tackling this in the other direction (making Function.prototype.toString output for built-in and/or other non-[[SourceText]] callables more deterministic), I would be happy to abandon this PR in favor of such a replacement.

gibson042 avatar Jul 14 '22 21:07 gibson042

@gibson042 See related: https://github.com/tc39/Function-prototype-toString-revision/issues/21#issuecomment-269954023

michaelficarra avatar Jul 14 '22 21:07 michaelficarra

Right. That issue was never resolved, and it's not clear to me how it would be without implementer commitment to align.

gibson042 avatar Jul 14 '22 22:07 gibson042

Per the July 2022 TC39 meeting, this should be replaced with https://github.com/tc39/proposal-stricter-function-tostring .

gibson042 avatar Aug 04 '22 18:08 gibson042