@@ -5293,8 +5293,7 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
52935293
52945294 @override
52955295 js_ast.Expression visitInstanceInvocation (InstanceInvocation node) {
5296- var invocation = _emitMethodCall (
5297- node.receiver, node.interfaceTarget, node.arguments, node);
5296+ var invocation = _emitInstanceInvocation (node);
52985297 return _isNullCheckableJsInterop (node.interfaceTarget)
52995298 ? _wrapWithJsInteropNullCheck (invocation)
53005299 : invocation;
@@ -5303,13 +5302,64 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
53035302 @override
53045303 js_ast.Expression visitInstanceGetterInvocation (
53055304 InstanceGetterInvocation node) {
5306- var getterInvocation = _emitMethodCall (
5307- node.receiver, node.interfaceTarget, node.arguments, node);
5305+ if (node.functionType == null ) {
5306+ // A `null` here implies the receiver must be typed as `dynamic` or
5307+ // `Function`. There isn't any more type information available at compile
5308+ // time to know this invocation is sound so a dynamic call will handle the
5309+ // checks at runtime.
5310+ return _emitDynamicInvocation (
5311+ node.receiver, node.name.text, node.arguments);
5312+ }
5313+ var getterInvocation = _emitInstanceGetterInvocation (node);
53085314 return _isNullCheckableJsInterop (node.interfaceTarget)
53095315 ? _wrapWithJsInteropNullCheck (getterInvocation)
53105316 : getterInvocation;
53115317 }
53125318
5319+ js_ast.Expression _emitInstanceGetterInvocation (
5320+ InstanceGetterInvocation node) {
5321+ var receiver = _visitExpression (node.receiver);
5322+ var arguments =
5323+ _emitArgumentList (node.arguments, target: node.interfaceTarget);
5324+ if (node.name.text == 'call' ) {
5325+ // Erasing the extension types here to support existing callable behavior
5326+ // on the old style JS interop types that are callable. This should be
5327+ // safe as it is a compile time error to try to dynamically invoke a call
5328+ // method that is inherited from an extension type.
5329+ var receiverType =
5330+ node.receiver.getStaticType (_staticTypeContext).extensionTypeErasure;
5331+ if (_isDirectCallable (receiverType)) {
5332+ // Call methods on function types should be handled as function calls.
5333+ return js_ast.Call (receiver, arguments);
5334+ }
5335+ }
5336+ var memberName =
5337+ _emitMemberName (node.name.text, member: node.interfaceTarget);
5338+ // We must erase the extension type to potentially find the `call` method.
5339+ // If the extension type has a runtime representation with a `call`:
5340+ //
5341+ // ```
5342+ // extension type Ext(C c) implements C {...}
5343+ // class C {
5344+ // call() {...}
5345+ // }
5346+ // ```
5347+ //
5348+ // We can always erase eagerly because:
5349+ // - Extension types that do not implement an interface that exposes a
5350+ // `call` method will result in a static error at the call site.
5351+ // - Calls to extension types that implement their own call method are
5352+ // lowered by the CFE to top level static method calls.
5353+ var erasedGetterType = node.interfaceTarget.getterType.extensionTypeErasure;
5354+ if (erasedGetterType is InterfaceType ) {
5355+ var callName = _implicitCallTarget (erasedGetterType);
5356+ if (callName != null ) {
5357+ return js.call ('#.#.#(#)' , [receiver, memberName, callName, arguments]);
5358+ }
5359+ }
5360+ return js.call ('#.#(#)' , [receiver, memberName, arguments]);
5361+ }
5362+
53135363 @override
53145364 js_ast.Expression visitLocalFunctionInvocation (LocalFunctionInvocation node) {
53155365 assert (node.name.text == 'call' );
@@ -5330,20 +5380,15 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
53305380 negated: false );
53315381 }
53325382
5333- js_ast.Expression _emitMethodCall (Expression receiver, Member target,
5334- Arguments arguments, InvocationExpression node) {
5335- var name = node.name.text;
5336-
5383+ js_ast.Expression _emitInstanceInvocation (InstanceInvocation node) {
53375384 /// Returns `true` when [node] represents an invocation of `List.add()` that
53385385 /// can be optimized.
53395386 ///
53405387 /// The optimized add operation can skip checks for a growable or modifiable
53415388 /// list and the element type is known to be invariant so it can skip the
53425389 /// type check.
5343- bool isNativeListInvariantAdd (InvocationExpression node) {
5344- if (node is InstanceInvocation &&
5345- node.isInvariant &&
5346- node.name.text == 'add' ) {
5390+ bool isNativeListInvariantAdd (InstanceInvocation node) {
5391+ if (node.isInvariant && node.name.text == 'add' ) {
53475392 // The call to add is marked as invariant, so the type check on the
53485393 // parameter to add is not needed.
53495394 var receiver = node.receiver;
@@ -5373,6 +5418,10 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
53735418 return false ;
53745419 }
53755420
5421+ var name = node.name.text;
5422+ var receiver = node.receiver;
5423+ var arguments = node.arguments;
5424+ var target = node.interfaceTarget;
53765425 if (isOperatorMethodName (name) && arguments.named.isEmpty) {
53775426 var argLength = arguments.positional.length;
53785427 if (argLength == 0 ) {
@@ -5382,75 +5431,33 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
53825431 receiver, target, arguments.positional[0 ], node);
53835432 }
53845433 }
5385-
53865434 var jsReceiver = _visitExpression (receiver);
53875435 var args = _emitArgumentList (arguments, target: target);
5388-
53895436 if (isNativeListInvariantAdd (node)) {
53905437 return js.call ('#.push(#)' , [jsReceiver, args]);
53915438 }
5392-
5393- var isCallingDynamicField = target.hasGetter &&
5394- // Erasing extension types here doesn't make sense. If there is an
5395- // extension type on dynamic or Function it will only be callable if it
5396- // defines a call method which would be invoked statically.
5397- _isDynamicOrFunction (target.getterType);
53985439 if (name == 'call' ) {
53995440 // Erasing the extension types here to support existing callable behavior
54005441 // on the old style JS interop types that are callable. This should be
54015442 // safe as it is a compile time error to try to dynamically invoke a call
54025443 // method that is inherited from an extension type.
54035444 var receiverType =
54045445 receiver.getStaticType (_staticTypeContext).extensionTypeErasure;
5405- if (isCallingDynamicField) {
5406- return _emitDynamicInvocation (receiver, name, arguments);
5407- }
54085446 if (_isDirectCallable (receiverType)) {
5409- // Call methods on function types should be handled as function calls.
5447+ // Handle call methods on function types as function calls.
54105448 return js_ast.Call (jsReceiver, args);
54115449 }
54125450 }
5413-
5414- var jsName = _emitMemberName (name, member: target);
5415-
5416- // Handle Object methods that are supported by `null` and potentially
5417- // JavaScript interop values.
5418- if (_isObjectMethodCall (name, arguments)) {
5419- if (_shouldCallObjectMemberHelper (receiver)) {
5420- // The names of the static helper methods in the runtime must match the
5421- // names of the Object instance members.
5422- return _runtimeCall ('#(#, #)' , [name, jsReceiver, args]);
5423- }
5424- // Otherwise generate this as a normal typed method call.
5425- } else if (isCallingDynamicField) {
5426- return _emitDynamicInvocation (receiver, name, arguments);
5427- }
5428- // TODO(jmesserly): remove when Kernel desugars this for us.
5429- // Handle `o.m(a)` where `o.m` is a getter returning a class with `call`.
5430- if (target is Field || target is Procedure && target.isAccessor) {
5431- // We must erase the extension type to find the `call` method.
5432- // If the extension type has a runtime representation with a `call`:
5433- //
5434- // ```
5435- // extension type Ext(C c) implements C {...}
5436- // class C {
5437- // call() {...}
5438- // }
5439- // ```
5440- //
5441- // We can always erase eagerly because:
5442- // - Extension types that do not implement an interface that exposes a
5443- // `call` method will result in a static error at the call site.
5444- // - Calls to extension types that implement their own call method are
5445- // lowered by the CFE to top level static method calls.
5446- var fromType = target.getterType.extensionTypeErasure;
5447- if (fromType is InterfaceType ) {
5448- var callName = _implicitCallTarget (fromType);
5449- if (callName != null ) {
5450- return js.call ('#.#.#(#)' , [jsReceiver, jsName, callName, args]);
5451- }
5452- }
5451+ if (_isObjectMethodCall (name, arguments) &&
5452+ _shouldCallObjectMemberHelper (receiver)) {
5453+ // Handle Object methods that are supported by `null` and possibly
5454+ // JavaScript interop values with static helper methods.
5455+ // The names of the static helper methods in the runtime must match the
5456+ // names of the Object instance members.
5457+ return _runtimeCall ('#(#, #)' , [name, jsReceiver, args]);
54535458 }
5459+ // Otherwise generate this as a normal typed method call.
5460+ var jsName = _emitMemberName (name, member: target);
54545461 return js.call ('#.#(#)' , [jsReceiver, jsName, args]);
54555462 }
54565463
@@ -5505,11 +5512,6 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
55055512 return null ;
55065513 }
55075514
5508- bool _isDynamicOrFunction (DartType t) =>
5509- DartTypeEquivalence (_coreTypes, ignoreTopLevelNullability: true )
5510- .areEqual (t, _coreTypes.functionNonNullableRawType) ||
5511- t == const DynamicType ();
5512-
55135515 js_ast.Expression _emitUnaryOperator (
55145516 Expression expr, Member ? target, InvocationExpression node) {
55155517 var op = node.name.text;
0 commit comments