Ticket #26 (new defect)

Opened 2 years ago

Last modified 1 year ago

The "arguments" object must alias formal positional parameters

Reported by: lth Assigned to: graydon
Type: defect Priority: major
Milestone: M2 Component: RefImpl
Version: 4 Keywords:
Cc: brendan, jeffdyer, edwsmith, lth

Description

Test code:

>> function f(x) { arguments[0] = 17; print(x) }
>> f(10)
10

The expected output is "17".

Attachments

Change History

Changed 1 year ago by jeffdyer

  • owner set to graydon

Changed 1 year ago by graydon

This is actually a fair bit more complicated than it looks. Is it necessary? What does it mean when there is destructuring assignment? Currently the arguments array is a lazy copy of the incoming (pre-name-binding, pre-destructuring) argument values.

Changed 1 year ago by brendan

  • cc set to brendan
  • summary changed from The "arguments" object must shadow formal parameters to The "arguments" object must alias formal parameters

Yes, this is necessary, but there may be confusion due to destructuring introducing local var bindings. See

http://developer.mozilla.org/es4/proposals/destructuring_assignment.html#formal_parameter_lists

especially the Notes, for the details. IOW, the formal parameter names spelled out in a destructuring pattern are *not* aliased by arguments[0 .. (arguments.length-1)]. Here's a SpiderMonkey? destructuring/aliasing example:

js> function f([a, b]){arguments[0]=42;print(a,b,arguments[0])} js> f([1,2]) 1 2 42

There's only one (unnamed) formal parameter slot aliased to arguments[0], and mutating via the arguments[0] alias can't happen until the function's destructuring prolog has run, and its body is evaluated. By that point, the formal that received the array actual has been used to destructur elements 0 and 1 into the var bindings named a and b.

Destructuring is see-through sugar, in this and other ways.

/be

Changed 1 year ago by brendan

  • summary changed from The "arguments" object must alias formal parameters to The "arguments" object must alias formal positional parameters

Changed 1 year ago by graydon

The refimpl currently treats all formal names the same way, whether introduced by destructuring patterns or plain variable bindings. In all cases, actual arguments are assigned to anonymous temporaries, then copied into formals (possibly via complex destructuring loads).

For this issue to be addressed as you describe, we'll need to treat "pattern" bindings and "non-pattern" bindings differently. This is a lot of work to undo. Jeff will need to modify the parser and definer.

Changed 1 year ago by brendan

  • cc changed from brendan to brendan, jeffdyer

Do you need to undo work, or just add an arguments array for the destructuring case?

Put another way, does the current RI actually use var bindings for the formal names in a destructuring parameter, per the proposal? It sounds like not.

/be

Changed 1 year ago by jeffdyer

  • cc changed from brendan, jeffdyer to brendan, jeffdyer, edwsmith

Let me see if I understand. In the case that there is a single parameter binding, that name needs to be aliased by the corresponding element of the arguments object, or vice versa. Currently storage for parameters is allocated in temporaries numbered 0 through n-1 where n is the number of formals. The value there is copied into a named property (or properties in the case of destructuring) which is the what is updated upon write to the parameter name. I haven't looked at the implementation of 'arguments', but I'm guessing it makes a copy of the original value too. So even without desugaring this is a problem, as demonstrated by Lars' original tests case above.

I think the desugaring case is pretty straightforward to fix once we fix the simpler non-destructuring case. What is missing is way to create alias fixtures (and properties). I need these for import aliasing too. With that, the parameter bindings could alias the corresponding temporary and the arguments object slots could do the same.

In the case of desugaring, we continue to create the non-aliasign value fixture with an initial value form the temporary.

So to summarize, if I have it right, we need to:

  • add a kind of fixture that results in a property alias that can reference temporary or named properties
  • for each non-desugaring parameter, create one of these aliases for each parameter temp
  • for each element of the arguments object that corresponds to a argument for which there is a parameter temporary, do the same

Of course depending on the configuration of the function, some or all of this machinery can be compiled out.

[adding ed since i have a vague recollection of our discussing arguments aliasing in AS3, about 2 years ago. to make sure we are aware of any incompatibilities]

Changed 1 year ago by brendan

Consider this case:

js> function f(a,b){print(arguments[2]);arguments[2]=42;return arguments[2]} js> f(1,2,3) 3 42

Here arguments[2] indeed aliases the third actual parameter, even though it lacks a formal parameter. So arguments is not just a copy of formal parameter values.

In the destructuring case, arguments can be used to access the undestructured object or array actual parameter. It's a view on the incoming actuals that aliases formals that correspond one-to-one with actuals.

/be

Changed 1 year ago by brendan

Hrm, copy/paste newline lossage. Trying again:

js> function f(a,b) {
  print(arguments[2]);
  arguments[2]=42;
  return arguments[2];
}
js> f(1,2,3)
3
42

/be

Changed 1 year ago by brendan

  • cc changed from brendan, jeffdyer, edwsmith to brendan, jeffdyer, edwsmith, lth

Making sure lth agrees.

/be

Changed 1 year ago by brendan

Hah! lars reported this. Oh well, I've got his attention now.

/be

Changed 1 year ago by jeffdyer

  • milestone changed from M0 to M1

Changed 1 year ago by lth

Brendan, we're in full agreement.

Changed 1 year ago by jeffdyer

  • milestone changed from M1 to M2

moving to M2. need to evaluate the SM tests to see the impact of removing it from the RI all together. In general, we don't think it is necessary to RI deprecated features.

Changed 1 year ago by brendan

Note to arguments specifiers/reference-implementors, or maybe just note to self:

We should make elements not be DontEnum?, to match Array element enumerability. The DontEnum? botch from ES1 daze is the subject of

https://bugzilla.mozilla.org/show_bug.cgi?id=352203

/be

Note: See TracTickets for help on using tickets.