Skip to content

Commit c31a282

Browse files
nshahanCommit Queue
authored and
Commit Queue
committed
Revert "[ddc] Refactor visitInstanceGetterInvocation()"
This reverts commit 776c058. Reason for revert: Broke test in google3 Original change's description: > [ddc] Refactor `visitInstanceGetterInvocation()` > > Moves the remaining special case logic out of `_emitMethodCall()` > simplifying the reasoning about where so hot reload soundness checks > can be added. > > Change-Id: I13e2f451e61f6e067ea689bcc35039cf92946492 > Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/423603 > Reviewed-by: Mark Zhou <[email protected]> > Reviewed-by: Nate Biggs <[email protected]> > Commit-Queue: Nicholas Shahan <[email protected]> Change-Id: I67d35d085e9b9510547aff8fb16ac0a8ed44d6df Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/425404 Reviewed-by: Srujan Gaddam <[email protected]> Commit-Queue: Nicholas Shahan <[email protected]> Bot-Commit: Rubber Stamper <[email protected]>
1 parent 201fcca commit c31a282

File tree

2 files changed

+137
-142
lines changed

2 files changed

+137
-142
lines changed

pkg/dev_compiler/lib/src/kernel/compiler.dart

+69-71
Original file line numberDiff line numberDiff line change
@@ -5293,7 +5293,8 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
52935293

52945294
@override
52955295
js_ast.Expression visitInstanceInvocation(InstanceInvocation node) {
5296-
var invocation = _emitInstanceInvocation(node);
5296+
var invocation = _emitMethodCall(
5297+
node.receiver, node.interfaceTarget, node.arguments, node);
52975298
return _isNullCheckableJsInterop(node.interfaceTarget)
52985299
? _wrapWithJsInteropNullCheck(invocation)
52995300
: invocation;
@@ -5302,64 +5303,13 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
53025303
@override
53035304
js_ast.Expression visitInstanceGetterInvocation(
53045305
InstanceGetterInvocation 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);
5306+
var getterInvocation = _emitMethodCall(
5307+
node.receiver, node.interfaceTarget, node.arguments, node);
53145308
return _isNullCheckableJsInterop(node.interfaceTarget)
53155309
? _wrapWithJsInteropNullCheck(getterInvocation)
53165310
: getterInvocation;
53175311
}
53185312

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-
53635313
@override
53645314
js_ast.Expression visitLocalFunctionInvocation(LocalFunctionInvocation node) {
53655315
assert(node.name.text == 'call');
@@ -5380,15 +5330,20 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
53805330
negated: false);
53815331
}
53825332

5383-
js_ast.Expression _emitInstanceInvocation(InstanceInvocation node) {
5333+
js_ast.Expression _emitMethodCall(Expression receiver, Member target,
5334+
Arguments arguments, InvocationExpression node) {
5335+
var name = node.name.text;
5336+
53845337
/// Returns `true` when [node] represents an invocation of `List.add()` that
53855338
/// can be optimized.
53865339
///
53875340
/// The optimized add operation can skip checks for a growable or modifiable
53885341
/// list and the element type is known to be invariant so it can skip the
53895342
/// type check.
5390-
bool isNativeListInvariantAdd(InstanceInvocation node) {
5391-
if (node.isInvariant && node.name.text == 'add') {
5343+
bool isNativeListInvariantAdd(InvocationExpression node) {
5344+
if (node is InstanceInvocation &&
5345+
node.isInvariant &&
5346+
node.name.text == 'add') {
53925347
// The call to add is marked as invariant, so the type check on the
53935348
// parameter to add is not needed.
53945349
var receiver = node.receiver;
@@ -5418,10 +5373,6 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
54185373
return false;
54195374
}
54205375

5421-
var name = node.name.text;
5422-
var receiver = node.receiver;
5423-
var arguments = node.arguments;
5424-
var target = node.interfaceTarget;
54255376
if (isOperatorMethodName(name) && arguments.named.isEmpty) {
54265377
var argLength = arguments.positional.length;
54275378
if (argLength == 0) {
@@ -5431,33 +5382,75 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
54315382
receiver, target, arguments.positional[0], node);
54325383
}
54335384
}
5385+
54345386
var jsReceiver = _visitExpression(receiver);
54355387
var args = _emitArgumentList(arguments, target: target);
5388+
54365389
if (isNativeListInvariantAdd(node)) {
54375390
return js.call('#.push(#)', [jsReceiver, args]);
54385391
}
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);
54395398
if (name == 'call') {
54405399
// Erasing the extension types here to support existing callable behavior
54415400
// on the old style JS interop types that are callable. This should be
54425401
// safe as it is a compile time error to try to dynamically invoke a call
54435402
// method that is inherited from an extension type.
54445403
var receiverType =
54455404
receiver.getStaticType(_staticTypeContext).extensionTypeErasure;
5405+
if (isCallingDynamicField) {
5406+
return _emitDynamicInvocation(receiver, name, arguments);
5407+
}
54465408
if (_isDirectCallable(receiverType)) {
5447-
// Handle call methods on function types as function calls.
5409+
// Call methods on function types should be handled as function calls.
54485410
return js_ast.Call(jsReceiver, args);
54495411
}
54505412
}
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]);
5458-
}
5459-
// Otherwise generate this as a normal typed method call.
5413+
54605414
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+
}
5453+
}
54615454
return js.call('#.#(#)', [jsReceiver, jsName, args]);
54625455
}
54635456

@@ -5512,6 +5505,11 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
55125505
return null;
55135506
}
55145507

5508+
bool _isDynamicOrFunction(DartType t) =>
5509+
DartTypeEquivalence(_coreTypes, ignoreTopLevelNullability: true)
5510+
.areEqual(t, _coreTypes.functionNonNullableRawType) ||
5511+
t == const DynamicType();
5512+
55155513
js_ast.Expression _emitUnaryOperator(
55165514
Expression expr, Member? target, InvocationExpression node) {
55175515
var op = node.name.text;

0 commit comments

Comments
 (0)