Chromium Code Reviews| Index: pkg/compiler/lib/src/kernel/element_map_impl.dart |
| diff --git a/pkg/compiler/lib/src/kernel/element_map_impl.dart b/pkg/compiler/lib/src/kernel/element_map_impl.dart |
| index 657a162ed08cfde080b4265fb7fe237a71f3cb19..a1ef51ae5833f3856f6161d978526355215e2565 100644 |
| --- a/pkg/compiler/lib/src/kernel/element_map_impl.dart |
| +++ b/pkg/compiler/lib/src/kernel/element_map_impl.dart |
| @@ -463,6 +463,116 @@ abstract class KernelToElementMapBase extends KernelToElementMapBaseMixin { |
| context.typeArguments, _getThisType(context.element).typeArguments); |
| } |
| + void _ensureCallType(IndexedClass cls, ClassData data) { |
| + if (!data.isCallTypeComputed) { |
| + data.isCallTypeComputed = true; |
| + MemberEntity callMethod = lookupClassMember(cls, Identifiers.call); |
| + if (callMethod != null) { |
| + if (callMethod.isFunction) { |
| + data.callType = _getFunctionType(callMethod); |
| + } else { |
| + data.callType = const DynamicType(); |
| + } |
| + return; |
| + } |
| + |
| + Set<FunctionType> inheritedCallTypes = new Set<FunctionType>(); |
| + bool inheritsInvalidCallMember = false; |
| + |
| + void addCallType(InterfaceType supertype) { |
| + if (supertype == null) return; |
| + DartType type = _getCallType(supertype); |
| + if (type == null) return; |
| + if (type.isFunctionType) { |
| + inheritedCallTypes.add(type); |
| + } else { |
| + inheritsInvalidCallMember = true; |
| + } |
| + } |
| + |
| + addCallType(_getSuperType(cls)); |
| + _getInterfaces(cls).forEach(addCallType); |
| + |
| + if (inheritsInvalidCallMember) { |
| + data.callType = const DynamicType(); |
| + } else if (inheritedCallTypes.isEmpty) { |
| + return; |
| + } else if (inheritedCallTypes.length == 1) { |
| + data.callType = inheritedCallTypes.single; |
| + } else { |
| + List<FunctionType> subtypesOfAllInherited = <FunctionType>[]; |
|
Siggi Cherem (dart-lang)
2017/08/11 16:14:59
I am not sure it is worth it to replicate this log
Johnni Winther
2017/08/15 14:17:37
It's there. It works. And at some point Issue 3043
|
| + outer: |
| + for (FunctionType a in inheritedCallTypes) { |
| + for (FunctionType b in inheritedCallTypes) { |
| + if (identical(a, b)) continue; |
| + if (!types.isSubtype(a, b)) continue outer; |
|
Siggi Cherem (dart-lang)
2017/08/11 16:14:59
Assuming we still want to keep this logic, this pa
Johnni Winther
2017/08/15 14:17:37
For (int)->void and (num)->void both subtype the o
Siggi Cherem (dart-lang)
2017/08/15 18:10:27
but bivariance is not allowed in strong mode :)
F
|
| + } |
| + subtypesOfAllInherited.add(a); |
| + } |
| + if (subtypesOfAllInherited.length == 1) { |
| + data.callType = subtypesOfAllInherited.single; |
| + return; |
| + } |
| + |
| + // Multiple signatures with different types => create the synthesized |
| + // version. |
|
Siggi Cherem (dart-lang)
2017/08/11 16:14:59
Here too - even if we keep the lookup for a glb an
Johnni Winther
2017/08/15 14:17:37
It is actually following the spec directly. Added
|
| + int minRequiredParameters; |
| + int maxPositionalParameters; |
| + Set<String> names = new Set<String>(); |
| + for (FunctionType type in inheritedCallTypes) { |
| + type.namedParameters.forEach((String name) => names.add(name)); |
| + int requiredParameters = type.parameterTypes.length; |
| + int optionalParameters = type.optionalParameterTypes.length; |
| + int positionalParameters = requiredParameters + optionalParameters; |
| + if (minRequiredParameters == null || |
| + minRequiredParameters > requiredParameters) { |
| + minRequiredParameters = requiredParameters; |
| + } |
| + if (maxPositionalParameters == null || |
| + maxPositionalParameters < positionalParameters) { |
| + maxPositionalParameters = positionalParameters; |
| + } |
| + } |
| + int optionalParameters = |
| + maxPositionalParameters - minRequiredParameters; |
| + // TODO(johnniwinther): Support function types with both optional |
| + // and named parameters? |
| + if (optionalParameters == 0 || names.isEmpty) { |
| + DartType dynamic = const DynamicType(); |
| + List<DartType> requiredParameterTypes = |
| + new List.filled(minRequiredParameters, dynamic); |
| + List<DartType> optionalParameterTypes = |
| + new List.filled(optionalParameters, dynamic); |
| + List<String> namedParameters = names.toList() |
| + ..sort((a, b) => a.compareTo(b)); |
| + List<DartType> namedParameterTypes = |
| + new List.filled(namedParameters.length, dynamic); |
| + data.callType = new FunctionType(dynamic, requiredParameterTypes, |
| + optionalParameterTypes, namedParameters, namedParameterTypes); |
| + } else { |
| + // The function type is not valid. |
| + data.callType = const DynamicType(); |
| + } |
| + } |
| + } |
| + } |
| + |
| + /// Returns the type of the `call` method on 'type'. |
| + /// |
| + /// If [type] doesn't have a `call` member `null` is returned. If [type] has |
| + /// an invalid `call` member (non-method or a synthesized method with both |
| + /// optional and named parameters) a [DynamicType] is returned. |
| + DartType _getCallType(InterfaceType type) { |
| + IndexedClass cls = type.element; |
| + assert(checkFamily(cls)); |
| + ClassData data = _classData[cls.classIndex]; |
| + _ensureCallType(cls, data); |
| + if (data.callType != null) { |
| + return _substByContext(data.callType, type); |
| + } |
| + return null; |
| + } |
| + |
| InterfaceType _getThisType(IndexedClass cls) { |
| assert(checkFamily(cls)); |
| ClassData data = _classData[cls.classIndex]; |
| @@ -1111,6 +1221,20 @@ class KernelToElementMapForImpactImpl extends KernelToElementMapBase |
| name, memberContext, executableContext, functionType); |
| }); |
| } |
| + |
| + bool _implementsFunction(IndexedClass cls) { |
| + assert(checkFamily(cls)); |
| + ClassData data = _classData[cls.classIndex]; |
| + OrderedTypeSet orderedTypeSet = data.orderedTypeSet; |
| + InterfaceType supertype = orderedTypeSet.asInstanceOf( |
| + commonElements.functionClass, |
| + _getHierarchyDepth(commonElements.functionClass)); |
| + if (supertype != null) { |
| + return true; |
| + } |
| + _ensureCallType(cls, data); |
| + return data.callType is FunctionType; |
| + } |
| } |
| class KernelElementEnvironment implements ElementEnvironment { |
| @@ -1541,8 +1665,7 @@ class KernelResolutionWorldBuilder extends KernelResolutionWorldBuilderBase { |
| @override |
| bool implementsFunction(ClassEntity cls) { |
| - // TODO(redemption): Implement this. |
| - return false; |
| + return elementMap._implementsFunction(cls); |
| } |
| @override |