@@ -6519,12 +6519,96 @@ class LibraryCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
65196519
65206520 @override
65216521 js_ast.Expression visitInstanceInvocation (InstanceInvocation node) {
6522- var invocation = _emitInstanceInvocation (node);
6522+ var target = node.interfaceTarget;
6523+ if (target.isPrimitiveOperator) {
6524+ return _emitPrimitiveOperatorInvocation (node);
6525+ }
6526+ var receiver = node.receiver;
6527+ var jsReceiver = _visitExpression (receiver);
6528+ var jsArguments = _emitArgumentList (node.arguments, target: target);
6529+ if (node.isNativeListInvariantAddInvocation (_coreTypes.listClass)) {
6530+ // TODO(nshahan): If this code is retained, can it become invalid after a
6531+ // hot reload?
6532+ return js.call ('#.push(#)' , [jsReceiver, jsArguments]);
6533+ }
6534+ var name = node.name.text;
6535+ if (name == 'call' ) {
6536+ var directCallInvocation = _emitDirectInstanceCallInvocation (node);
6537+ if (directCallInvocation != null ) {
6538+ return directCallInvocation;
6539+ }
6540+ }
6541+ if (target.isToStringOrNoSuchMethodWithDefaultSignature &&
6542+ _shouldCallObjectMemberHelper (receiver)) {
6543+ // Handle Object methods when the receiver could potentially be `null` or
6544+ // JavaScript interop values with static helper methods.
6545+ // The names of the static helper methods in the runtime must match the
6546+ // names of the Object instance members.
6547+ // TODO(nshahan): What should be checked after a hot reload. I think only
6548+ // the return type of the NSM can change.
6549+ return _runtimeCall ('#(#, #)' , [name, jsReceiver, jsArguments]);
6550+ }
6551+ // Otherwise generate this as a normal typed method call.
6552+ var jsName = _emitMemberName (name, member: target);
6553+ var invocation = js.call ('#.#(#)' , [jsReceiver, jsName, jsArguments]);
65236554 return _isNullCheckableJsInterop (node.interfaceTarget)
65246555 ? _wrapWithJsInteropNullCheck (invocation)
65256556 : invocation;
65266557 }
65276558
6559+ /// Returns a direct invocation to support a `call()` method invocation when
6560+ /// the receiver is considered directly callable, otherwise returns
6561+ /// `null` .
6562+ ///
6563+ /// For example if `fn` is statically typed as a function type, then
6564+ /// `fn.call()` would be considered directly callable and compiled as `fn()` .
6565+ // TODO(nshahan): Handle retained call method invocations that have new
6566+ // signatures or were deleted after a hot reload.
6567+ js_ast.Expression ? _emitDirectInstanceCallInvocation (
6568+ InstanceInvocation node,
6569+ ) {
6570+ // Erasing the extension types here to support existing callable behavior
6571+ // on the old style JS interop types that are callable. This should be
6572+ // safe as it is a compile time error to try to dynamically invoke a call
6573+ // method that is inherited from an extension type.
6574+ var receiverType = node.receiver
6575+ .getStaticType (_staticTypeContext)
6576+ .extensionTypeErasure;
6577+ if (! _isDirectCallable (receiverType)) return null ;
6578+ // Handle call methods on function types as function calls.
6579+ var invocation = js_ast.Call (
6580+ _visitExpression (node.receiver),
6581+ _emitArgumentList (node.arguments, target: node.interfaceTarget),
6582+ );
6583+ return _isNullCheckableJsInterop (node.interfaceTarget)
6584+ ? _wrapWithJsInteropNullCheck (invocation)
6585+ : invocation;
6586+ }
6587+
6588+ /// Returns an invocation of a primitive operator.
6589+ ///
6590+ /// See [ProcedureHelpers.isPrimitiveOperator] .
6591+ // TODO(nshahan): Handle retained operator invocations that have new
6592+ // signatures or were deleted after a hot reload.
6593+ js_ast.Expression _emitPrimitiveOperatorInvocation (InstanceInvocation node) {
6594+ var receiver = node.receiver;
6595+ var target = node.interfaceTarget;
6596+ var arguments = node.arguments;
6597+ assert (arguments.types.isEmpty && arguments.named.isEmpty);
6598+ // JavaScript interop does not support overloading of these operators.
6599+ return switch (arguments.positional.length) {
6600+ 0 => _emitUnaryOperator (receiver, target, node),
6601+ 1 => _emitBinaryOperator (receiver, target, arguments.positional[0 ], node),
6602+ // Should always be a compile time error but here for exhaustiveness.
6603+ _ => throw UnsupportedError (
6604+ 'Invalid number of positional arguments.\n '
6605+ 'Found: ${arguments .positional .length }\n '
6606+ 'Operator: ${node .name .text } '
6607+ '${node .location }' ,
6608+ ),
6609+ };
6610+ }
6611+
65286612 @override
65296613 js_ast.Expression visitInstanceGetterInvocation (
65306614 InstanceGetterInvocation node,
@@ -6624,55 +6708,6 @@ class LibraryCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
66246708 ], negated: false );
66256709 }
66266710
6627- js_ast.Expression _emitInstanceInvocation (InstanceInvocation node) {
6628- var name = node.name.text;
6629- var receiver = node.receiver;
6630- var arguments = node.arguments;
6631- var target = node.interfaceTarget;
6632- if (target.isPrimitiveOperator && arguments.named.isEmpty) {
6633- var argLength = arguments.positional.length;
6634- if (argLength == 0 ) {
6635- return _emitUnaryOperator (receiver, target, node);
6636- } else if (argLength == 1 ) {
6637- return _emitBinaryOperator (
6638- receiver,
6639- target,
6640- arguments.positional[0 ],
6641- node,
6642- );
6643- }
6644- }
6645- var jsReceiver = _visitExpression (receiver);
6646- var args = _emitArgumentList (arguments, target: target);
6647- if (node.isNativeListInvariantAddInvocation (_coreTypes.listClass)) {
6648- return js.call ('#.push(#)' , [jsReceiver, args]);
6649- }
6650- if (name == 'call' ) {
6651- // Erasing the extension types here to support existing callable behavior
6652- // on the old style JS interop types that are callable. This should be
6653- // safe as it is a compile time error to try to dynamically invoke a call
6654- // method that is inherited from an extension type.
6655- var receiverType = receiver
6656- .getStaticType (_staticTypeContext)
6657- .extensionTypeErasure;
6658- if (_isDirectCallable (receiverType)) {
6659- // Handle call methods on function types as function calls.
6660- return js_ast.Call (jsReceiver, args);
6661- }
6662- }
6663- if (target.isToStringOrNoSuchMethodWithDefaultSignature &&
6664- _shouldCallObjectMemberHelper (receiver)) {
6665- // Handle Object methods when the receiver could potentially be `null` or
6666- // JavaScript interop values with static helper methods.
6667- // The names of the static helper methods in the runtime must match the
6668- // names of the Object instance members.
6669- return _runtimeCall ('#(#, #)' , [name, jsReceiver, args]);
6670- }
6671- // Otherwise generate this as a normal typed method call.
6672- var jsName = _emitMemberName (name, member: target);
6673- return js.call ('#.#(#)' , [jsReceiver, jsName, args]);
6674- }
6675-
66766711 /// Returns an invocation of the runtime helpers `dcall` , `dgcall` , `dsend` ,
66776712 /// or `dgsend` to perform dynamic checks before invoking [memberName] on
66786713 /// [receiver] and passing [arguments] .
0 commit comments