<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<!DOCTYPE bugzilla SYSTEM "https://bugs.webkit.org/page.cgi?id=bugzilla.dtd">

<bugzilla version="5.0.4.1"
          urlbase="https://bugs.webkit.org/"
          
          maintainer="admin@webkit.org"
>

    <bug>
          <bug_id>312466</bug_id>
          
          <creation_ts>2026-04-16 05:39:22 -0700</creation_ts>
          <short_desc>Promise.prototype.finally does not seem to observably assert whether IsConstructor(C) is true</short_desc>
          <delta_ts>2026-04-21 16:06:14 -0700</delta_ts>
          <reporter_accessible>1</reporter_accessible>
          <cclist_accessible>1</cclist_accessible>
          <classification_id>1</classification_id>
          <classification>Unclassified</classification>
          <product>WebKit</product>
          <component>JavaScriptCore</component>
          <version>Safari 18</version>
          <rep_platform>Mac (Apple Silicon)</rep_platform>
          <op_sys>macOS 15</op_sys>
          <bug_status>RESOLVED</bug_status>
          <resolution>FIXED</resolution>
          
          
          <bug_file_loc></bug_file_loc>
          <status_whiteboard></status_whiteboard>
          <keywords>InRadar</keywords>
          <priority>P2</priority>
          <bug_severity>Normal</bug_severity>
          <target_milestone>---</target_milestone>
          
          
          <everconfirmed>1</everconfirmed>
          <reporter name="Francisco Tolmasky">tolmasky</reporter>
          <assigned_to name="Tetsuharu Ohzeki [UTC+9]">tetsuharu.ohzeki</assigned_to>
          <cc>tetsuharu.ohzeki</cc>
    
    <cc>webkit-bug-importer</cc>
          

      

      

      

          <comment_sort_order>oldest_to_newest</comment_sort_order>  
          <long_desc isprivate="0" >
    <commentid>2201024</commentid>
    <comment_count>0</comment_count>
    <who name="Francisco Tolmasky">tolmasky</who>
    <bug_when>2026-04-16 05:39:22 -0700</bug_when>
    <thetext>The following line does not throw any errors in Safari (and just returns undefined), but *does* throw an error in Chrome and Firefox:

`Promise.prototype.finally.call({ constructor: { [Symbol.species]: () =&gt; 10 }, then() { } })`

If you run that line in Chrome you&apos;ll see that you get:

```
VM619:1 Uncaught TypeError: object.constructor[Symbol.species] is not a constructor
    at Object.finally (&lt;anonymous&gt;)
    at &lt;anonymous&gt;:1:27
```

In Firefox you get:

```
Uncaught TypeError: @@species property of object&apos;s constructor is not a constructor
    &lt;anonymous&gt; debugger eval code:1
```

The relevant part of the spec is found at step 4 of the promise.prototype.finally definition (https://tc39.es/ecma262/#sec-promise.prototype.finally), copied here:

&quot;4. Assert: IsConstructor(C) is true.&quot;

I believe that Safari&apos;s choice to not throw *is* technically allowed by the spec since the spec says that &quot;Asserts&quot; do not necessarily need to have any semantic effect, and thus both strategies seem acceptable. However I think it would be preferable for Safari to match Chrome and Firefox&apos;s behavior, both for interoperability reasons, but also because throwing when the assertion is false is actually quite useful. In particular, this is currently employed in the wild as a means to implement an &quot;IsConstructor&quot; function that is side-effect-free. That is to say, you can call IsConstructor(F) and be assured that F will never itself be called as a result. Unfortunately, techniques like using Reflect.construct(F, []) and checking for an error are *not* side-effect free in this way. They WILL call F F in the case where F *is* a constructor.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>2201031</commentid>
    <comment_count>1</comment_count>
    <who name="Francisco Tolmasky">tolmasky</who>
    <bug_when>2026-04-16 05:53:06 -0700</bug_when>
    <thetext>Another quick comment: it also arguably makes implementing a rock solid IsConstructor possible at all. Without it, you need to do the difficult task of filtering non-Reflect.construct not a constructor errors. Just as a quick example, Reflect.construct(Element, []) throws with &quot;illegal constructor&quot; just to show you how quickly you run into this sort of thing. Element is however detected perfectly fine with the Promise.prototype.finally method in the browsers that throw.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>2201084</commentid>
    <comment_count>2</comment_count>
    <who name="Tetsuharu Ohzeki [UTC+9]">tetsuharu.ohzeki</who>
    <bug_when>2026-04-16 09:36:59 -0700</bug_when>
    <thetext>I seem this case is covered by https://github.com/tc39/test262/blob/1775ee48c9d71fbd1ec6a1a66ac23efcbd627f8f/test/built-ins/Promise/prototype/finally/species-constructor-throws.js and it was imported in https://commits.webkit.org/308596@main, 

but the above test just checks what the thrown is just a TypeError, but not checking the detail of it. Its TypeError is caused by that mimic |this| lacks |then|.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>2201087</commentid>
    <comment_count>3</comment_count>
    <who name="Tetsuharu Ohzeki [UTC+9]">tetsuharu.ohzeki</who>
    <bug_when>2026-04-16 09:39:44 -0700</bug_when>
    <thetext>Pull request: https://github.com/WebKit/WebKit/pull/62901</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>2202929</commentid>
    <comment_count>4</comment_count>
    <who name="EWS">ews-feeder</who>
    <bug_when>2026-04-21 16:05:47 -0700</bug_when>
    <thetext>Committed 311725@main (e704581e3ddb): &lt;https://commits.webkit.org/311725@main&gt;

Reviewed commits have been landed. Closing PR #62901 and removing active labels.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>2202930</commentid>
    <comment_count>5</comment_count>
    <who name="Radar WebKit Bug Importer">webkit-bug-importer</who>
    <bug_when>2026-04-21 16:06:14 -0700</bug_when>
    <thetext>&lt;rdar://problem/175290627&gt;</thetext>
  </long_desc>
      
      

    </bug>

</bugzilla>