Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(711)

Unified Diff: pkg/compiler/lib/src/kernel/element_map_impl.dart

Issue 3000763002: Implement .getCallType (Closed)
Patch Set: Created 3 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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

Powered by Google App Engine
This is Rietveld 408576698