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

Unified Diff: pkg/compiler/lib/src/cps_ir/type_mask_system.dart

Issue 1316673006: dart2js cps: Use TypeMaskSystem when inserting refinement nodes. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Remove unused ClassElement variable && rebase Created 5 years, 3 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/cps_ir/type_mask_system.dart
diff --git a/pkg/compiler/lib/src/cps_ir/type_mask_system.dart b/pkg/compiler/lib/src/cps_ir/type_mask_system.dart
new file mode 100644
index 0000000000000000000000000000000000000000..a5fa5a8dc9618e51ca53f4b51496735ff404cdbf
--- /dev/null
+++ b/pkg/compiler/lib/src/cps_ir/type_mask_system.dart
@@ -0,0 +1,298 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library dart2js.type_mask_system;
+
+import '../closure.dart' show ClosureClassElement, Identifiers;
+import '../common/names.dart' show Selectors, Identifiers;
+import '../compiler.dart' as dart2js show Compiler;
+import '../constants/constant_system.dart';
+import '../constants/values.dart';
+import '../dart_types.dart' as types;
+import '../elements/elements.dart';
+import '../io/source_information.dart' show SourceInformation;
+import '../js_backend/js_backend.dart' show JavaScriptBackend;
+import '../types/types.dart';
+import '../types/constants.dart' show computeTypeMask;
+import '../universe/universe.dart';
+import '../world.dart' show World;
+
+enum AbstractBool {
+ True, False, Maybe, Nothing
+}
+
+class TypeMaskSystem {
+ final TypesTask inferrer;
+ final World classWorld;
+ final JavaScriptBackend backend;
+
+ TypeMask get dynamicType => inferrer.dynamicType;
+ TypeMask get typeType => inferrer.typeType;
+ TypeMask get functionType => inferrer.functionType;
+ TypeMask get boolType => inferrer.boolType;
+ TypeMask get intType => inferrer.intType;
+ TypeMask get doubleType => inferrer.doubleType;
+ TypeMask get numType => inferrer.numType;
+ TypeMask get stringType => inferrer.stringType;
+ TypeMask get listType => inferrer.listType;
+ TypeMask get mapType => inferrer.mapType;
+ TypeMask get nonNullType => inferrer.nonNullType;
+ TypeMask get nullType => inferrer.nullType;
+ TypeMask get extendableNativeListType => backend.extendableArrayType;
+
+ TypeMask numStringBoolType;
+
+ ClassElement get jsNullClass => backend.jsNullClass;
+
+ // TODO(karlklose): remove compiler here.
+ TypeMaskSystem(dart2js.Compiler compiler)
+ : inferrer = compiler.typesTask,
+ classWorld = compiler.world,
+ backend = compiler.backend {
+
+ // Build the number+string+bool type. To make containment tests more
+ // inclusive, we use the num, String, bool types for this, not
+ // the JSNumber, JSString, JSBool subclasses.
+ TypeMask anyNum =
+ new TypeMask.nonNullSubtype(classWorld.numClass, classWorld);
+ TypeMask anyString =
+ new TypeMask.nonNullSubtype(classWorld.stringClass, classWorld);
+ TypeMask anyBool =
+ new TypeMask.nonNullSubtype(classWorld.boolClass, classWorld);
+ numStringBoolType =
+ new TypeMask.unionOf(<TypeMask>[anyNum, anyString, anyBool],
+ classWorld);
+ }
+
+ bool methodUsesReceiverArgument(FunctionElement function) {
+ assert(backend.isInterceptedMethod(function));
+ ClassElement clazz = function.enclosingClass.declaration;
+ return clazz.isSubclassOf(backend.jsInterceptorClass) ||
+ classWorld.isUsedAsMixin(clazz);
+ }
+
+ Element locateSingleElement(TypeMask mask, Selector selector) {
+ return mask.locateSingleElement(selector, mask, classWorld.compiler);
+ }
+
+ ClassElement singleClass(TypeMask mask) {
+ return mask.singleClass(classWorld);
+ }
+
+ bool needsNoSuchMethodHandling(TypeMask mask, Selector selector) {
+ return mask.needsNoSuchMethodHandling(selector, classWorld);
+ }
+
+ TypeMask getReceiverType(MethodElement method) {
+ assert(method.isInstanceMember);
+ if (classWorld.isUsedAsMixin(method.enclosingClass.declaration)) {
+ // If used as a mixin, the receiver could be any of the classes that mix
+ // in the class, and these are not considered subclasses.
+ // TODO(asgerf): Exclude the subtypes that only `implement` the class.
+ return nonNullSubtype(method.enclosingClass);
+ } else {
+ return nonNullSubclass(method.enclosingClass);
+ }
+ }
+
+ TypeMask getParameterType(ParameterElement parameter) {
+ return inferrer.getGuaranteedTypeOfElement(parameter);
+ }
+
+ TypeMask getReturnType(FunctionElement function) {
+ return inferrer.getGuaranteedReturnTypeOfElement(function);
+ }
+
+ TypeMask getInvokeReturnType(Selector selector, TypeMask mask) {
+ return inferrer.getGuaranteedTypeOfSelector(selector, mask);
+ }
+
+ TypeMask getFieldType(FieldElement field) {
+ return inferrer.getGuaranteedTypeOfElement(field);
+ }
+
+ TypeMask join(TypeMask a, TypeMask b) {
+ return a.union(b, classWorld);
+ }
+
+ TypeMask getTypeOf(ConstantValue constant) {
+ return computeTypeMask(inferrer.compiler, constant);
+ }
+
+ TypeMask nonNullExact(ClassElement element) {
+ // The class world does not know about classes created by
+ // closure conversion, so just treat those as a subtypes of Function.
+ // TODO(asgerf): Maybe closure conversion should create a new ClassWorld?
+ if (element.isClosure) return functionType;
+ return new TypeMask.nonNullExact(element.declaration, classWorld);
+ }
+
+ TypeMask nonNullSubclass(ClassElement element) {
+ if (element.isClosure) return functionType;
+ return new TypeMask.nonNullSubclass(element.declaration, classWorld);
+ }
+
+ TypeMask nonNullSubtype(ClassElement element) {
+ if (element.isClosure) return functionType;
+ return new TypeMask.nonNullSubtype(element.declaration, classWorld);
+ }
+
+ bool isDefinitelyBool(TypeMask t, {bool allowNull: false}) {
+ if (!allowNull && t.isNullable) return false;
+ return t.nonNullable().containsOnlyBool(classWorld);
+ }
+
+ bool isDefinitelyNum(TypeMask t, {bool allowNull: false}) {
+ if (!allowNull && t.isNullable) return false;
+ return t.nonNullable().containsOnlyNum(classWorld);
+ }
+
+ bool isDefinitelyString(TypeMask t, {bool allowNull: false}) {
+ if (!allowNull && t.isNullable) return false;
+ return t.nonNullable().containsOnlyString(classWorld);
+ }
+
+ bool isDefinitelyNumStringBool(TypeMask t, {bool allowNull: false}) {
+ if (!allowNull && t.isNullable) return false;
+ return numStringBoolType.containsMask(t.nonNullable(), classWorld);
+ }
+
+ bool isDefinitelyNotNumStringBool(TypeMask t) {
+ return areDisjoint(t, numStringBoolType);
+ }
+
+ /// True if all values of [t] are either integers or not numbers at all.
+ ///
+ /// This does not imply that the value is an integer, since most other values
+ /// such as null are also not a non-integer double.
+ bool isDefinitelyNotNonIntegerDouble(TypeMask t) {
+ // Even though int is a subclass of double in the JS type system, we can
+ // still check this with disjointness, because [doubleType] is the *exact*
+ // double class, so this excludes things that are known to be instances of a
+ // more specific class.
+ // We currently exploit that there are no subclasses of double that are
+ // not integers (e.g. there is no UnsignedDouble class or whatever).
+ return areDisjoint(t, doubleType);
+ }
+
+ bool isDefinitelyInt(TypeMask t, {bool allowNull: false}) {
+ if (!allowNull && t.isNullable) return false;
+ return t.satisfies(backend.jsIntClass, classWorld);
+ }
+
+ bool isDefinitelyNativeList(TypeMask t, {bool allowNull: false}) {
+ if (!allowNull && t.isNullable) return false;
+ return t.nonNullable().satisfies(backend.jsArrayClass, classWorld);
+ }
+
+ bool isDefinitelyMutableNativeList(TypeMask t, {bool allowNull: false}) {
+ if (!allowNull && t.isNullable) return false;
+ return t.nonNullable().satisfies(backend.jsMutableArrayClass, classWorld);
+ }
+
+ bool isDefinitelyFixedNativeList(TypeMask t, {bool allowNull: false}) {
+ if (!allowNull && t.isNullable) return false;
+ return t.nonNullable().satisfies(backend.jsFixedArrayClass, classWorld);
+ }
+
+ bool isDefinitelyExtendableNativeList(TypeMask t, {bool allowNull: false}) {
+ if (!allowNull && t.isNullable) return false;
+ return t.nonNullable().satisfies(backend.jsExtendableArrayClass,
+ classWorld);
+ }
+
+ bool isDefinitelyIndexable(TypeMask t, {bool allowNull: false}) {
+ if (!allowNull && t.isNullable) return false;
+ return t.nonNullable().satisfies(backend.jsIndexableClass, classWorld);
+ }
+
+ bool areDisjoint(TypeMask leftType, TypeMask rightType) {
+ TypeMask intersection = leftType.intersection(rightType, classWorld);
+ return intersection.isEmpty && !intersection.isNullable;
+ }
+
+ AbstractBool isSubtypeOf(TypeMask value,
+ types.DartType type,
+ {bool allowNull}) {
+ assert(allowNull != null);
+ if (type is types.DynamicType) {
+ return AbstractBool.True;
+ }
+ if (type is types.InterfaceType) {
+ TypeMask typeAsMask = allowNull
+ ? new TypeMask.subtype(type.element, classWorld)
+ : new TypeMask.nonNullSubtype(type.element, classWorld);
+ if (areDisjoint(value, typeAsMask)) {
+ // Disprove the subtype relation based on the class alone.
+ return AbstractBool.False;
+ }
+ if (!type.treatAsRaw) {
+ // If there are type arguments, we cannot prove the subtype relation,
+ // because the type arguments are unknown on both the value and type.
+ return AbstractBool.Maybe;
+ }
+ if (typeAsMask.containsMask(value, classWorld)) {
+ // All possible values are contained in the set of allowed values.
+ // Note that we exploit the fact that [typeAsMask] is an exact
+ // representation of [type], not an approximation.
+ return AbstractBool.True;
+ }
+ // The value is neither contained in the type, nor disjoint from the type.
+ return AbstractBool.Maybe;
+ }
+ // TODO(asgerf): Support function types, and what else might be missing.
+ return AbstractBool.Maybe;
+ }
+
+ /// Returns whether [type] is one of the falsy values: false, 0, -0, NaN,
+ /// the empty string, or null.
+ AbstractBool boolify(TypeMask type) {
+ if (isDefinitelyNotNumStringBool(type) && !type.isNullable) {
+ return AbstractBool.True;
+ }
+ return AbstractBool.Maybe;
+ }
+
+ AbstractBool strictBoolify(TypeMask type) {
+ if (areDisjoint(type, boolType)) return AbstractBool.False;
+ return AbstractBool.Maybe;
+ }
+
+ /// Create a type mask containing at least all subtypes of [type].
+ TypeMask subtypesOf(types.DartType type) {
+ if (type is types.InterfaceType) {
+ ClassElement element = type.element;
+ if (element.isObject) {
+ return dynamicType;
+ }
+ if (element == classWorld.nullClass) {
+ return nullType;
+ }
+ if (element == classWorld.stringClass) {
+ return stringType;
+ }
+ if (element == classWorld.numClass ||
+ element == classWorld.doubleClass) {
+ return numType;
+ }
+ if (element == classWorld.intClass) {
+ return intType;
+ }
+ if (element == classWorld.boolClass) {
+ return boolType;
+ }
+ return new TypeMask.nonNullSubtype(element, classWorld);
+ }
+ if (type is types.FunctionType) {
+ return functionType;
+ }
+ return dynamicType;
+ }
+
+ /// Returns a subset of [mask] containing at least the types
+ /// that can respond to [selector] without throwing.
+ TypeMask receiverTypeFor(Selector selector, TypeMask mask) {
+ return classWorld.allFunctions.receiverType(selector, mask);
+ }
+}
« no previous file with comments | « pkg/compiler/lib/src/cps_ir/insert_refinements.dart ('k') | pkg/compiler/lib/src/cps_ir/type_propagation.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698