<html>
    <head>
      <base href="https://bugs.webkit.org/" />
    </head>
    <body><span class="vcard"><a class="email" href="mailto:eric.carlson&#64;apple.com" title="Eric Carlson &lt;eric.carlson&#64;apple.com&gt;"> <span class="fn">Eric Carlson</span></a>
</span> changed
              <a class="bz_bug_link 
          bz_status_NEW "
   title="NEW - WebRTC: Update RTCPeerConnection overloaded legacy operations to return a Promise"
   href="https://bugs.webkit.org/show_bug.cgi?id=158114">bug 158114</a>
        <br>
             <table border="1" cellspacing="0" cellpadding="8">
          <tr>
            <th>What</th>
            <th>Removed</th>
            <th>Added</th>
          </tr>

         <tr>
           <td style="text-align:right;">Attachment #279879 Flags</td>
           <td>
               &nbsp;
           </td>
           <td>review+
           </td>
         </tr></table>
      <p>
        <div>
            <b><a class="bz_bug_link 
          bz_status_NEW "
   title="NEW - WebRTC: Update RTCPeerConnection overloaded legacy operations to return a Promise"
   href="https://bugs.webkit.org/show_bug.cgi?id=158114#c4">Comment # 4</a>
              on <a class="bz_bug_link 
          bz_status_NEW "
   title="NEW - WebRTC: Update RTCPeerConnection overloaded legacy operations to return a Promise"
   href="https://bugs.webkit.org/show_bug.cgi?id=158114">bug 158114</a>
              from <span class="vcard"><a class="email" href="mailto:eric.carlson&#64;apple.com" title="Eric Carlson &lt;eric.carlson&#64;apple.com&gt;"> <span class="fn">Eric Carlson</span></a>
</span></b>
        <pre>Comment on <span class=""><a href="attachment.cgi?id=279879&amp;action=diff" name="attach_279879" title="Proposed patch">attachment 279879</a> <a href="attachment.cgi?id=279879&amp;action=edit" title="Proposed patch">[details]</a></span>
Proposed patch

View in context: <a href="https://bugs.webkit.org/attachment.cgi?id=279879&amp;action=review">https://bugs.webkit.org/attachment.cgi?id=279879&amp;action=review</a>

<span class="quote">&gt; LayoutTests/fast/mediastream/resources/promise-utils.js:18
&gt; +function promiseShouldResolve(expr) {</span >

This function is unused. Did you mean to use it, or is it for future use?

<span class="quote">&gt; Source/WebCore/Modules/mediastream/RTCPeerConnectionInternals.js:98
&gt; +function objectAndCallbacksOverload(args, functionName, objectConstructor, objectOptions, promiseMode, legacyMode)
&gt;  {
&gt;      &quot;use strict&quot;;
&gt;  
&gt; -    var options = {};
&gt; +    let argsCount = Math.min(3, args.length);
&gt; +    let objectArg = args[0];
&gt; +    let objectArgOk = false;
&gt; +
&gt; +    if (argsCount == 0 &amp;&amp; objectOptions.optionalAndNullable) {
&gt; +        objectArg = null;
&gt; +        objectArgOk = true;
&gt; +        argsCount = 1;
&gt; +    } else {
&gt; +        const hasMatchingType = objectArg instanceof objectConstructor;
&gt; +        objectArgOk = objectOptions.optionalAndNullable ? (objectArg === null || typeof objectArg === &quot;undefined&quot; || hasMatchingType) : hasMatchingType;
&gt; +    }
&gt;  
&gt; -    if (args.length &lt;= 1) {
&gt; -        // Promise mode
&gt; -        if (args.length &amp;&amp; &#64;isDictionary(args[0]))
&gt; -            options = args[0]
&gt; +    if (argsCount == 1 &amp;&amp; objectArgOk)
&gt; +        return promiseMode(objectArg);
&gt;  
&gt; -        return &#64;enqueueOperation(peerConnection, function () {
&gt; -            return targetFunction.&#64;call(peerConnection, options);
&gt; -        });
&gt; -    }
&gt; +    const successCallback = args[1];
&gt; +    const errorCallback = args[2];
&gt; +    if (argsCount == 3 &amp;&amp; objectArgOk
&gt; +        &amp;&amp; (successCallback == null || typeof successCallback === &quot;function&quot;)
&gt; +        &amp;&amp; (errorCallback == null || typeof errorCallback === &quot;function&quot;)) {
&gt; +        if (typeof successCallback !== &quot;function&quot;)
&gt; +            return &#64;Promise.&#64;reject(new &#64;TypeError(`Argument 2 ('successCallback') to RTCPeerConnection.${functionName} must be a function`));
&gt; +
&gt; +        if (typeof errorCallback !== &quot;function&quot;)
&gt; +            return &#64;Promise.&#64;reject(new &#64;TypeError(`Argument 3 ('errorCallback') to RTCPeerConnection.${functionName} must be a function`));
&gt;  
&gt; -    // Legacy callbacks mode (2 or 3 arguments)
&gt; -    var successCallback = &#64;extractCallbackArg(args, 0, &quot;successCallback&quot;, functionName);
&gt; -    var errorCallback = &#64;extractCallbackArg(args, 1, &quot;errorCallback&quot;, functionName);
&gt; +        return legacyMode(objectArg, successCallback, errorCallback);
&gt; +    }
&gt;  
&gt; -    if (args.length &gt; 2 &amp;&amp; &#64;isDictionary(args[2]))
&gt; -        options = args[2];
&gt; +    if (argsCount &lt; 1)
&gt; +        return &#64;Promise.&#64;reject(new &#64;TypeError(&quot;Not enough arguments&quot;));
&gt;  
&gt; -    &#64;enqueueOperation(peerConnection, function () {
&gt; -        return targetFunction.&#64;call(peerConnection, options).then(successCallback, errorCallback);
&gt; -    });
&gt; +    return &#64;Promise.&#64;reject(new &#64;TypeError(&quot;Type error&quot;));
&gt;  }</span >

I had a hard time figuring out this logic. I think it will be clearer if you restructure it to return early as soon as you know the arguments are valid or illegal. For example (untested so this may not be exactly correct):


function objectAndCallbacksOverload(args, functionName, objectConstructor, objectOptions, promiseMode, legacyMode)
{
    &quot;use strict&quot;;

    let argsCount = Math.min(3, args.length);
    let objectArg = args[0];
    let objectArgOk = false;

    if (!argsCount &amp;&amp; objectOptions.optionalAndNullable) {
        objectArg = null;
        objectArgOk = true;
        argsCount = 1;
    } else {
        const hasMatchingType = objectArg instanceof objectConstructor;
        objectArgOk = objectOptions.optionalAndNullable ? (objectArg === null || typeof objectArg === &quot;undefined&quot; || hasMatchingType) : hasMatchingType;
    }

    if (argsCount &lt; 1)
        return &#64;Promise.&#64;reject(new &#64;TypeError(&quot;Not enough arguments&quot;));

    if (argsCount == 1 &amp;&amp; objectArgOk)
        return promiseMode(objectArg);

    if (argsCount != 3 || !objectArgOk)
        return &#64;Promise.&#64;reject(new &#64;TypeError(&quot;Type error&quot;));

    const successCallback = args[1];
    if (successCallback != null &amp;&amp; typeof errorCallback !== &quot;function&quot;)
        return &#64;Promise.&#64;reject(new &#64;TypeError(`Argument 2 ('successCallback') to RTCPeerConnection.${functionName} must be a function`));

    const errorCallback = args[2];
    if (errorCallback != null &amp;&amp; typeof errorCallback !== &quot;function&quot;))
        return &#64;Promise.&#64;reject(new &#64;TypeError(`Argument 3 ('errorCallback') to RTCPeerConnection.${functionName} must be a function`));

    return legacyMode(objectArg, successCallback, errorCallback);
}

<span class="quote">&gt; Source/WebCore/Modules/mediastream/RTCPeerConnectionInternals.js:123
&gt; +    const argsCount = Math.min(3, args.length);
&gt;  
&gt; -    // Legacy callbacks mode (3 arguments)
&gt; -    if (args.length &lt; 3)
&gt; -        throw new &#64;TypeError(&quot;Not enough arguments&quot;);
&gt; +    if (argsCount == 0 || argsCount == 1)
&gt; +        return promiseMode(args[0]);
&gt;  
&gt; -    var successCallback = &#64;extractCallbackArg(args, 1, &quot;successCallback&quot;, functionName);
&gt; -    var errorCallback = &#64;extractCallbackArg(args, 2, &quot;errorCallback&quot;, functionName);
&gt; -
&gt; -    &#64;enqueueOperation(peerConnection, function () {
&gt; -        return targetFunction.&#64;call(peerConnection, description).then(successCallback, errorCallback);
&gt; -    });
&gt; -}
&gt; +    const successCallback = args[0];
&gt; +    const errorCallback = args[1];
&gt; +    if ((argsCount == 2 || argsCount == 3)
&gt; +        &amp;&amp; (successCallback == null || typeof successCallback === &quot;function&quot;)
&gt; +        &amp;&amp; (errorCallback == null || typeof errorCallback === &quot;function&quot;)) {
&gt; +        if (typeof successCallback !== &quot;function&quot;)
&gt; +            return &#64;Promise.&#64;reject(new &#64;TypeError(`Argument 1 ('successCallback') to RTCPeerConnection.${functionName} must be a function`));
&gt;  
&gt; -function extractCallbackArg(args, index, name, parentFunctionName)
&gt; -{
&gt; -    &quot;use strict&quot;;
&gt; +        if (typeof errorCallback !== &quot;function&quot;)
&gt; +            return &#64;Promise.&#64;reject(new &#64;TypeError(`Argument 2 ('errorCallback') to RTCPeerConnection.${functionName} must be a function`));
&gt;  
&gt; -    var callback = args[index];
&gt; -    if (typeof callback !== &quot;function&quot;)
&gt; -        throw new &#64;TypeError(&quot;Argument &quot; + (index + 1) + &quot; ('&quot; + name + &quot;') to RTCPeerConnection.&quot; + parentFunctionName + &quot; must be a Function&quot;);
&gt; +        return legacyMode(successCallback, errorCallback, args[2]);
&gt; +    }
&gt;  
&gt; -    return callback;
&gt; +    return &#64;Promise.&#64;reject(new &#64;TypeError(&quot;Type error&quot;));</span >

I think this would be slightly clearer if you reject for an unexpected number of arguments immediately after getting the argument count.</pre>
        </div>
      </p>
      <hr>
      <span>You are receiving this mail because:</span>
      
      <ul>
          <li>You are the assignee for the bug.</li>
      </ul>
    </body>
</html>