@@ -3047,7 +3047,10 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
3047
3047
/// Arguments which are _directly_ wrapped at the site they are passed are
3048
3048
/// unmodified.
3049
3049
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;
3051
3054
if (type is FunctionType ||
3052
3055
(type is InterfaceType && type.classNode == _coreTypes.functionClass)) {
3053
3056
if (! isAllowInterop (f)) {
@@ -5493,6 +5496,7 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
5493
5496
return false ;
5494
5497
}
5495
5498
5499
+ // TODO(54463): Refactor and specialize this code for each type of 'get'.
5496
5500
js_ast.Expression _emitPropertyGet (
5497
5501
Expression receiver, Member ? member, String memberName) {
5498
5502
// TODO(jmesserly): should tearoff of `.call` on a function type be
@@ -5526,8 +5530,11 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
5526
5530
}
5527
5531
// Otherwise generate this as a normal typed property get.
5528
5532
} 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.
5531
5538
receiver.getStaticType (_staticTypeContext) is ! RecordType ) {
5532
5539
return runtimeCall ('dload$_replSuffix (#, #)' , [jsReceiver, jsName]);
5533
5540
}
@@ -5765,9 +5772,17 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
5765
5772
5766
5773
var isCallingDynamicField = target is Member &&
5767
5774
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.
5768
5778
_isDynamicOrFunction (target.getterType);
5769
5779
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;
5771
5786
if (isCallingDynamicField || _isDynamicOrFunction (receiverType)) {
5772
5787
return _emitDynamicInvoke (jsReceiver, null , args, arguments);
5773
5788
} else if (_isDirectCallable (receiverType)) {
@@ -5793,7 +5808,22 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
5793
5808
// TODO(jmesserly): remove when Kernel desugars this for us.
5794
5809
// Handle `o.m(a)` where `o.m` is a getter returning a class with `call`.
5795
5810
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;
5797
5827
if (fromType is InterfaceType ) {
5798
5828
var callName = _implicitCallTarget (fromType);
5799
5829
if (callName != null ) {
0 commit comments