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

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

Issue 3000763002: Implement .getCallType (Closed)
Patch Set: The fix 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 8437fe8f7ab200849ff3ea9817ce8b4567448e81..ce3e0a511430a76d55c2782c835149c203c8e6b3 100644
--- a/pkg/compiler/lib/src/kernel/element_map_impl.dart
+++ b/pkg/compiler/lib/src/kernel/element_map_impl.dart
@@ -459,6 +459,146 @@ abstract class KernelToElementMapBase extends KernelToElementMapBaseMixin {
context.typeArguments, _getThisType(context.element).typeArguments);
}
+ // TODO(johnniwinther): Remove this when call-type is provided by fasta.
+ 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);
+
+ // Following §11.1.1 in the spec.
+ if (inheritsInvalidCallMember) {
+ // From §11.1.1 in the spec (continued):
+ //
+ // If some but not all of the m_i, 1 ≤ i ≤ k are getters none of the m_i
+ // are inherited, and a static warning is issued.
+ data.callType = const DynamicType();
+ } else if (inheritedCallTypes.isEmpty) {
+ return;
+ } else if (inheritedCallTypes.length == 1) {
+ data.callType = inheritedCallTypes.single;
+ } else {
+ // From §11.1.1 in the spec (continued):
+ //
+ // Otherwise, if the static types T_1, ... , T_k of the members
+ // m_1, ..., m_k are not identical, then there must be a member m_x such
+ // that T_x <: T_i, 1 ≤ x ≤ k for all i ∈ 1..k, or a static type warning
+ // occurs.
+ List<FunctionType> subtypesOfAllInherited = <FunctionType>[];
+ outer:
+ for (FunctionType a in inheritedCallTypes) {
+ for (FunctionType b in inheritedCallTypes) {
+ if (identical(a, b)) continue;
+ if (!types.isSubtype(a, b)) continue outer;
+ }
+ subtypesOfAllInherited.add(a);
+ }
+ if (subtypesOfAllInherited.length == 1) {
+ // From §11.1.1 in the spec (continued):
+ //
+ // The member that is inherited is m_x, if it exists.
+ data.callType = subtypesOfAllInherited.single;
+ return;
+ }
+
+ // From §11.1.1 in the spec (continued):
+ //
+ // Otherwise: let numberOfPositionals(f) denote the number of
+ // positional parameters of a function f, and let
+ // numberOfRequiredParams(f) denote the number of required parameters of
+ // a function f. Furthermore, let s denote the set of all named
+ // parameters of the m_1, . . . , m_k. Then let
+ //
+ // h = max(numberOfPositionals(mi)),
+ // r = min(numberOfRequiredParams(mi)), i ∈ 1..k.
+
+ // Then I has a method named n, with r required parameters of type
+ // dynamic, h positional parameters of type dynamic, named parameters s
+ // of type dynamic and return type dynamic.
+
+ // Multiple signatures with different types => create the synthesized
+ // version.
+ 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];
@@ -1107,6 +1247,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 {
@@ -1537,8 +1691,7 @@ class KernelResolutionWorldBuilder extends KernelResolutionWorldBuilderBase {
@override
bool implementsFunction(ClassEntity cls) {
- // TODO(redemption): Implement this.
- return false;
+ return elementMap._implementsFunction(cls);
}
@override
« no previous file with comments | « pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart ('k') | pkg/compiler/lib/src/kernel/env.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698