Skip to content

Commit 4c9c298

Browse files
domenictobie
authored andcommitted
Update attribute setters and getters (#217)
- Fixes getters on the global when no explicit `this` is passed, similarly to what was already done for operations in a2b4599. Closes https://www.w3.org/Bugs/Public/show_bug.cgi?id=29421. - Make promise getters reject in case of an error. Disallow promise types on attributes that will generate setters. Fixes #186 and fixes https://www.w3.org/Bugs/Public/show_bug.cgi?id=25048. As part of this, disallowed [SameObject] for promise-returning attributes, since different promises will be returned if the getter is used incorrectly. - Fixes https://www.w3.org/Bugs/Public/show_bug.cgi?id=27905 by more clearly specifying the target (as was done previously for operations). - Updated to use modern ES Get/Set abstract operations instead of [[Get]] and [[Put]]. - Also made minor fixes to the operations definition.
1 parent 0c5f48b commit 4c9c298

File tree

2 files changed

+580
-542
lines changed

2 files changed

+580
-542
lines changed

index.bs

+121-105
Original file line numberDiff line numberDiff line change
@@ -1377,6 +1377,10 @@ ignored or an exception is thrown.
13771377
};
13781378
</pre>
13791379

1380+
Attributes whose type is a [=promise type=] must be [=read only=]. Additionally, they cannot have
1381+
any of the [=extended attributes=] [{{LenientThis}}], [{{PutForwards}}], [{{Replaceable}}], or
1382+
[{{SameObject}}].
1383+
13801384
A [=regular attribute=]
13811385
that is not [=read only=]
13821386
can be declared to <dfn id="dfn-inherit-getter" export>inherit its getter</dfn>
@@ -10518,126 +10522,138 @@ The characteristics of this property are as follows:
1051810522
where:
1051910523
* |configurable| is <emu-val>false</emu-val> if the attribute was
1052010524
declared with the [{{Unforgeable}}] extended attribute and <emu-val>true</emu-val> otherwise;
10521-
* |G| is the [=attribute getter=], defined below; and
10522-
* |S| is the [=attribute setter=], also defined below.
10523-
* <div algorithm>
10524-
10525-
The <dfn id="dfn-attribute-getter" export>attribute getter</dfn> is a <emu-val>Function</emu-val>
10526-
object whose behavior when invoked is as follows:
10527-
10528-
1. Let |idlValue| be an IDL value determined as follows.
10529-
1. If the [=attribute=] is a [=regular attribute=], then:
10530-
1. Let |I| be the [=interface=]
10531-
whose [=interface prototype object=]
10532-
this property corresponding to the attribute appears on.
10533-
10534-
Note: This means that even if an implements statement was used to make
10535-
an attribute available on the interface, |I| is the interface
10536-
on the left hand side of the implements statement, and not the one
10537-
that the attribute was originally declared on.
10538-
10539-
1. Let |O| be the <emu-val>this</emu-val> value.
10540-
1. If |O| is a [=platform object=],
10541-
then [=perform a security check=], passing:
10542-
* the platform object |O|,
10543-
* the [=identifier=] of the [=attribute=], and
10544-
* the type “getter”.
10545-
1. If |O| is not a [=platform object=] that implements |I|, then:
10546-
1. If the [=attribute=] was specified with the
10547-
[{{LenientThis}}] [=extended attribute=],
10548-
then return <emu-val>undefined</emu-val>.
10549-
1. Otherwise, [=ECMAScript/throw=] a <emu-val>TypeError</emu-val>.
10550-
1. Set |idlValue| to be the result of performing the actions listed in the description of the attribute that occur when getting
10551-
(or those listed in the description of the inherited attribute, if this attribute is declared to
10552-
[=inherit its getter=]),
10553-
with |O| as the object.
10554-
1. Otherwise, the attribute is a [=static attribute=].
10555-
Set |idlValue| to be the result of performing the actions listed in the description of the attribute that occur when getting.
10556-
1. Let |V| be the result of [=converted to an ECMAScript value|converting=]
10557-
|idlValue| to an ECMAScript value.
10558-
1. Return |V|.
10559-
</div>
10525+
* |G| is the [=attribute getter=] created given the attribute, the interface (or the interface
10526+
it's being mixed in to, if the interface is actually a mixin), and the [=relevant Realm=] of
10527+
the object that is the location of the property; and
10528+
* |S| is the [=attribute setter=] created given the attribute, the interface (or the interface
10529+
it's being mixed in to, if the interface is actually a mixin), and the [=relevant Realm=] of
10530+
the object that is the location of the property.
1056010531

10561-
The value of the <emu-val>Function</emu-val> object’s “length”
10562-
property is the <emu-val>Number</emu-val> value <emu-val>0</emu-val>.
10532+
<div algorithm>
1056310533

10564-
The value of the <emu-val>Function</emu-val> object’s “name”
10565-
property is a <emu-val>String</emu-val> whose value is the
10566-
concatenation of “get ” and the identifier of the attribute.
10534+
The <dfn id="dfn-attribute-getter" export>attribute getter</dfn> is created as follows, given an
10535+
[=attribute=] |attribute|, an [=interface=] |target|, and a [=Realm=] |realm|:
1056710536

10568-
* <div algorithm>
10537+
1. Let |steps| be the following series of steps:
10538+
1. Try running the following steps:
10539+
1. Let |O| be <emu-val>null</emu-val>.
10540+
1. If |attribute| is a [=regular attribute=]:
10541+
1. If the <emu-val>this</emu-val> value is <emu-val>null</emu-val> or
10542+
<emu-val>undefined</emu-val>, set |O| to |realm|'s [=Realm/global object=].
10543+
(This will subsequently cause a <emu-val>TypeError</emu-val> in a few steps, if
10544+
the global object does not implement |target| and [{{LenientThis}}] is not
10545+
specified.)
10546+
<!-- https://www.w3.org/Bugs/Public/show_bug.cgi?id=18547#c9 -->
10547+
1. Otherwise, set |O| to the <emu-val>this</emu-val> value.
10548+
1. If |O| is a [=platform object=], then [=perform a security check=], passing |O|,
10549+
|attribute|'s [=identifier=], and "getter".
10550+
1. If |O| is not a [=platform object=] that implements the interface |target|,
10551+
then:
10552+
1. If |attribute| was specified with the [{{LenientThis}}]
10553+
[=extended attribute=], then return <emu-val>undefined</emu-val>.
10554+
1. Otherwise, [=ECMAScript/throw=] a <emu-val>TypeError</emu-val>.
10555+
1. Let |R| be the result of performing the actions listed in the
10556+
description of |attribute| that occur on getting (or those listed in the description
10557+
of the inherited attribute, if this attribute is declared to
10558+
[=inherit its getter=]), on |O| if |O| is not <emu-val>null</emu-val>.
10559+
1. Return the result of [=converted to an ECMAScript value|converting=] |R| to an
10560+
ECMAScript value of the type |attribute| is declared as.
1056910561

10570-
The <dfn id="dfn-attribute-setter" export>attribute setter</dfn> is <emu-val>undefined</emu-val>
10571-
if the attribute is declared <code>readonly</code> and does not have a
10572-
[{{LenientThis}}], [{{PutForwards}}] or [{{Replaceable}}] [=extended attribute=]
10573-
declared on it.
10574-
Otherwise, it is a <emu-val>Function</emu-val> object whose behavior when invoked is as follows:
10562+
And then, if an exception was thrown:
1057510563

10576-
1. If no arguments were passed to the <emu-val>Function</emu-val>, then
10577-
[=ECMAScript/throw=] a <emu-val>TypeError</emu-val>.
10578-
1. Let |V| be the value of the first argument passed to the <emu-val>Function</emu-val>.
10579-
1. If the [=attribute=] is a [=regular attribute=], then:
10580-
1. Let |I| be the [=interface=]
10581-
whose [=interface prototype object=]
10582-
this property corresponding to the attribute appears on.
10583-
1. Let |O| be the <emu-val>this</emu-val> value.
10584-
1. If |O| is a [=platform object=],
10585-
then [=perform a security check=], passing:
10586-
* the platform object |O|,
10587-
* the [=identifier=] of the [=attribute=], and
10588-
* the type “setter”.
10589-
1. Let |validThis| be <emu-val>true</emu-val> if |O| is a
10590-
[=platform object=] that implements |I|, or
10591-
<emu-val>false</emu-val> otherwise.
10592-
1. If |validThis| is <emu-val>false</emu-val> and the
10593-
[=attribute=] was not specified with the
10594-
[{{LenientThis}}] [=extended attribute=],
10595-
then [=ECMAScript/throw=] a <emu-val>TypeError</emu-val>.
10596-
1. If the attribute is declared with a [{{Replaceable}}]
10597-
extended attribute, then:
10598-
1. Let |P| be the identifier of the attribute.
10599-
1. Call [=CreateDataProperty=](|O|, |P|, |V|).
10564+
1. If |attribute|'s type is a [=promise type=], then:
10565+
1. Let |reject| be the initial value of [=%Promise%=].reject.
10566+
1. Return the result of calling |reject| with [=%Promise%=] as the
10567+
<emu-val>this</emu-val> object and the exception as the single argument value.
10568+
1. Otherwise, end these steps and allow the exception to propagate.
10569+
1. Let |F| be [=!=] [=CreateBuiltinFunction=](|realm|,
10570+
|steps|, the [=%FunctionPrototype%=] of |realm|).
10571+
1. Let |name| be the string "get " prepended to |attribute|'s [=identifier=].
10572+
1. Perform [=!=] [=SetFunctionName=](|F|, |name|).
10573+
1. Perform [=!=] [=DefinePropertyOrThrow=](|F|, "length",
10574+
PropertyDescriptor<span class="prop-desc">{\[[Value]]: 0, \[[Writable]]: <emu-val>false</emu-val>, \[[Enumerable]]: <emu-val>false</emu-val>, \[[Configurable]]: <emu-val>true</emu-val>}</span>).
10575+
1. Return |F|.
10576+
10577+
</div>
10578+
10579+
<div algorithm>
10580+
10581+
The <dfn id="dfn-attribute-setter" export>attribute setter</dfn> is created as follows, given an
10582+
[=attribute=] |attribute|, an [=interface=] |target|, and a [=Realm=] |realm|:
10583+
10584+
1. If |attribute| is [=read only=] and does not have a
10585+
[{{LenientThis}}], [{{PutForwards}}] or [{{Replaceable}}] [=extended attribute=], return
10586+
<emu-val>undefined</emu-val>; there is no [=attribute setter=] function.
10587+
1. Assert: |attribute|'s type is not a [=promise type=].
10588+
1. Let |steps| be the following series of steps:
10589+
1. If no arguments were passed, then [=ECMAScript/throw=] a <emu-val>TypeError</emu-val>.
10590+
1. Let |V| be the value of the first argument passed.
10591+
1. Let |id| be |attribute|'s [=identifier=].
10592+
1. Let |O| be <emu-val>null</emu-val>.
10593+
1. If |attribute| is a [=regular attribute=]:
10594+
1. If the <emu-val>this</emu-val> value is <emu-val>null</emu-val> or
10595+
<emu-val>undefined</emu-val>, set |O| to |realm|'s [=Realm/global object=].
10596+
(This will subsequently cause a <emu-val>TypeError</emu-val> in a few steps, if
10597+
the global object does not implement |target| and [{{LenientThis}}] is not
10598+
specified.)
10599+
<!-- https://www.w3.org/Bugs/Public/show_bug.cgi?id=18547#c9 -->
10600+
1. Otherwise, set |O| to the <emu-val>this</emu-val> value.
10601+
1. If |O| is a [=platform object=], then [=perform a security check=], passing |O|,
10602+
|id|, and "setter".
10603+
1. Let |validThis| be true if |O| is a [=platform object=] that implements the
10604+
interface |target|, or false otherwise.
10605+
1. If |validThis| is false and |attribute| was not specified with the [{{LenientThis}}]
10606+
[=extended attribute=], then [=ECMAScript/throw=] a <emu-val>TypeError</emu-val>.
10607+
1. If |attribute| is declared with the [{{Replaceable}}] extended attribute, then:
10608+
1. Perform [=?=] [=CreateDataProperty=](|O|, |id|, |V|).
1060010609
1. Return <emu-val>undefined</emu-val>.
10601-
1. If |validThis| is <emu-val>false</emu-val>, then return <emu-val>undefined</emu-val>.
10602-
1. If the attribute is declared with a [{{LenientSetter}}]
10603-
extended attribute, then return <emu-val>undefined</emu-val>.
10604-
1. If the attribute is declared with a [{{PutForwards}}]
10605-
extended attribute, then:
10606-
1. Let |Q| be the result of calling the \[[Get]] method
10607-
on |O| using the identifier of the attribute as the property name.
10608-
1. If |Q| is not an object, then [=ECMAScript/throw=] a <emu-val>TypeError</emu-val>.
10609-
1. Let |A| be the attribute identified by the [{{PutForwards}}] extended attribute.
10610-
1. Call the \[[Put]] method on |Q|
10611-
using the identifier of |A| as the property name and |V| as the value.
10610+
1. If |validThis| is false, then return <emu-val>undefined</emu-val>.
10611+
1. If |attribute| is declared with a [{{LenientSetter}}] extended attribute, then
10612+
return <emu-val>undefined</emu-val>.
10613+
1. If |attribute| is declared with a [{{PutForwards}}] extended attribute, then:
10614+
1. Let |Q| be [=?=] [=Get=](|O|, |id|).
10615+
1. If [=Type=](|Q|) is not Object, then [=ECMAScript/throw=] a
10616+
<emu-val>TypeError</emu-val>.
10617+
1. Let |forwardId| be the identifier argument of the [{{PutForwards}}] extended
10618+
attribute.
10619+
1. Perform [=?=] [=Set=](|Q|, |forwardId|, |V|).
1061210620
1. Return <emu-val>undefined</emu-val>.
10613-
1. Let |idlValue| be an IDL value determined as follows:
10614-
* If the type of the attribute is an [=enumeration=], then:
10615-
1. Let |S| be the result of calling [=ToString=](|V|).
10616-
1. If |S| is not one of the [=enumeration values|enumeration’s values=], then return <emu-val>undefined</emu-val>.
10617-
1. The value of |idlValue| is the enumeration value equal to |S|.
10618-
* Otherwise, the type of the attribute is not an [=enumeration=].
10619-
The value of |idlValue| is the result of [=converted to an IDL value|converting=]
10620-
|V| to an IDL value.
10621-
1. If the attribute is a regular attribute, then perform the actions listed in the description of the attribute that occur when setting,
10622-
with |O| as the object and |idlValue| as the value.
10623-
1. Otherwise, the attribute is a [=static attribute=].
10624-
Perform the actions listed in the description of the attribute that occur when setting with |idlValue| as the value.
10625-
1. Return <emu-val>undefined</emu-val>.
10626-
</div>
10621+
1. Let |idlValue| be determined as follows:
1062710622

10628-
The value of the <emu-val>Function</emu-val> object’s “length”
10629-
property is the <emu-val>Number</emu-val> value <emu-val>1</emu-val>.
10623+
<dl class="switch">
10624+
<dt>|attribute|'s type is an [=enumeration=]</dt>
10625+
<dd>
10626+
1. Let |S| be [=?=] [=ToString=](|V|).
10627+
1. If |S| is not one of the [=enumeration values|enumeration’s values=], then
10628+
return <emu-val>undefined</emu-val>.
10629+
1. Otherwise, |idlValue| is the enumeration value equal to |S|.
10630+
</dd>
10631+
10632+
<dt>Otherwise</dt>
10633+
<dd>
10634+
|idlValue| is the result of [=converted to an IDL value|converting=] |V| to an
10635+
IDL value of |attribute|'s type.
10636+
</dd>
10637+
</dl>
1063010638

10631-
The value of the <emu-val>Function</emu-val> object’s “name”
10632-
property is a <emu-val>String</emu-val> whose value is the
10633-
concatenation of “set ” and the identifier of the attribute.
10639+
1. Perform the actions listed in the description of |attribute| that occur on setting, on
10640+
|O| if |O| is not <emu-val>null</emu-val>.
10641+
1. Return <emu-val>undefined</emu-val>
10642+
1. Let |F| be [=!=] [=CreateBuiltinFunction=](|realm|,
10643+
|steps|, the [=%FunctionPrototype%=] of |realm|).
10644+
1. Let |name| be the string "set " prepended to |id|.
10645+
1. Perform [=!=] [=SetFunctionName=](|F|, |name|).
10646+
1. Perform [=!=] [=DefinePropertyOrThrow=](|F|, "length",
10647+
PropertyDescriptor<span class="prop-desc">{\[[Value]]: 1, \[[Writable]]: <emu-val>false</emu-val>, \[[Enumerable]]: <emu-val>false</emu-val>, \[[Configurable]]: <emu-val>true</emu-val>}</span>).
10648+
1. Return |F|.
10649+
</div>
1063410650

1063510651
Note: Although there is only a single property for an IDL attribute, since
1063610652
accessor property getters and setters are passed a <emu-val>this</emu-val>
1063710653
value for the object on which property corresponding to the IDL attribute is
1063810654
accessed, they are able to expose instance-specific data.
1063910655

10640-
Note: Note that attempting to assign to a property corresponding to a
10656+
Note: Attempting to assign to a property corresponding to a
1064110657
[=read only=] [=attribute=]
1064210658
results in different behavior depending on whether the script doing so is in strict mode.
1064310659
When in strict mode, such an assignment will result in a <emu-val>TypeError</emu-val>

0 commit comments

Comments
 (0)