Skip to content

Commit ced57aa

Browse files
nshahanCommit Queue
authored and
Commit Queue
committed
[ddc] Handle extension types in more locations
Either erased the extension type or documented why it seems erasure is not needed. Issue: #49735 Change-Id: Ic6c2fcaebaf10570691b95a383b8ad2e40d2061a Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/343720 Reviewed-by: Srujan Gaddam <[email protected]> Commit-Queue: Nicholas Shahan <[email protected]>
1 parent ab9a746 commit ced57aa

File tree

1 file changed

+35
-5
lines changed

1 file changed

+35
-5
lines changed

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

+35-5
Original file line numberDiff line numberDiff line change
@@ -3047,7 +3047,10 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
30473047
/// Arguments which are _directly_ wrapped at the site they are passed are
30483048
/// unmodified.
30493049
Expression _assertInterop(Expression f) {
3050-
var type = f.getStaticType(_staticTypeContext);
3050+
// Erasing any extension types here for legacy JS interop support but if
3051+
// using the new extension type interop the type system requires that
3052+
// `.toJS` was called.
3053+
var type = f.getStaticType(_staticTypeContext).extensionTypeErasure;
30513054
if (type is FunctionType ||
30523055
(type is InterfaceType && type.classNode == _coreTypes.functionClass)) {
30533056
if (!isAllowInterop(f)) {
@@ -5493,6 +5496,7 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
54935496
return false;
54945497
}
54955498

5499+
// TODO(54463): Refactor and specialize this code for each type of 'get'.
54965500
js_ast.Expression _emitPropertyGet(
54975501
Expression receiver, Member? member, String memberName) {
54985502
// TODO(jmesserly): should tearoff of `.call` on a function type be
@@ -5526,8 +5530,11 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
55265530
}
55275531
// Otherwise generate this as a normal typed property get.
55285532
} else if (member == null &&
5529-
// Records have no member node for the element getters so avoid emitting
5530-
// a dynamic get when the types are known statically.
5533+
// Null member usually means this is a dynamic get but Records also have
5534+
// no member node for the element getters so avoid emitting a dynamic
5535+
// get when the types are known statically.
5536+
// Accesses of extension type getters don't lead to this code path
5537+
// at all so only the test for RecordType is needed.
55315538
receiver.getStaticType(_staticTypeContext) is! RecordType) {
55325539
return runtimeCall('dload$_replSuffix(#, #)', [jsReceiver, jsName]);
55335540
}
@@ -5765,9 +5772,17 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
57655772

57665773
var isCallingDynamicField = target is Member &&
57675774
target.hasGetter &&
5775+
// Erasing extension types here doesn't make sense. If there is an
5776+
// extension type on dynamic or Function it will only be callable if it
5777+
// defines a call method which would be invoked statically.
57685778
_isDynamicOrFunction(target.getterType);
57695779
if (name == 'call') {
5770-
var receiverType = receiver.getStaticType(_staticTypeContext);
5780+
// Erasing the extension types here to support existing callable behaivor
5781+
// on the old style JS interop types that are callable. This should be
5782+
// safe as it is a compile time error to try to dynamically invoke a call
5783+
// method that is inherited from an extension type.
5784+
var receiverType =
5785+
receiver.getStaticType(_staticTypeContext).extensionTypeErasure;
57715786
if (isCallingDynamicField || _isDynamicOrFunction(receiverType)) {
57725787
return _emitDynamicInvoke(jsReceiver, null, args, arguments);
57735788
} else if (_isDirectCallable(receiverType)) {
@@ -5793,7 +5808,22 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
57935808
// TODO(jmesserly): remove when Kernel desugars this for us.
57945809
// Handle `o.m(a)` where `o.m` is a getter returning a class with `call`.
57955810
if (target is Field || target is Procedure && target.isAccessor) {
5796-
var fromType = target!.getterType;
5811+
// We must erase the extension type to find the `call` method.
5812+
// If the extension type has a runtime representation with a `call`:
5813+
//
5814+
// ```
5815+
// extension type Ext(C c) implements C {...}
5816+
// class C {
5817+
// call() {...}
5818+
// }
5819+
// ```
5820+
//
5821+
// We can always erase eagerly becuase:
5822+
// - Extension types that do not implment an interface that exposes a
5823+
// `call` method will result in a static error at the call site.
5824+
// - Calls to extension types that implement their own call method are
5825+
// lowered by the CFE to top level static method calls.
5826+
var fromType = target!.getterType.extensionTypeErasure;
57975827
if (fromType is InterfaceType) {
57985828
var callName = _implicitCallTarget(fromType);
57995829
if (callName != null) {

0 commit comments

Comments
 (0)