Index: pkg/kernel/lib/type_propagation/type_propagation.dart |
diff --git a/pkg/kernel/lib/type_propagation/type_propagation.dart b/pkg/kernel/lib/type_propagation/type_propagation.dart |
deleted file mode 100644 |
index 8808c681185fd31e58750578cab562a1d4744543..0000000000000000000000000000000000000000 |
--- a/pkg/kernel/lib/type_propagation/type_propagation.dart |
+++ /dev/null |
@@ -1,168 +0,0 @@ |
-// Copyright (c) 2016, 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 kernel.type_propagation; |
- |
-import '../ast.dart'; |
-import '../class_hierarchy.dart'; |
-import '../core_types.dart'; |
-import 'builder.dart'; |
-import 'solver.dart'; |
- |
-/// High-level interface to type propagation. |
-/// |
-/// This exposes inferred types as [InferredValue], context-insensitively at |
-/// the level of function boundaries. The internal analysis results may be |
-/// more precise but their representation is private to the analysis, and |
-/// except for diagnostics, clients should only depend on the results exposed |
-/// by this interface. |
-// |
-// TODO(asgerf): Also expose return value of calls. |
-// TODO(asgerf): Should we expose the value of all expressions? |
-class TypePropagation { |
- final Builder builder; |
- final Solver solver; |
- |
- TypePropagation(Program program, |
- {ClassHierarchy hierarchy, CoreTypes coreTypes}) |
- : this.withBuilder( |
- new Builder(program, hierarchy: hierarchy, coreTypes: coreTypes)); |
- |
- TypePropagation.withBuilder(Builder builder) |
- : this.builder = builder, |
- this.solver = new Solver(builder)..solve(); |
- |
- InferredValue getFieldValue(Field node) { |
- int variable = builder.global.fields[node]; |
- if (variable == null) return null; |
- return solver.getValueInferredForVariable(variable); |
- } |
- |
- InferredValue getReturnValue(FunctionNode node) { |
- int variable = builder.global.returns[node]; |
- if (variable == null) return null; |
- return solver.getValueInferredForVariable(variable); |
- } |
- |
- InferredValue getParameterValue(VariableDeclaration node) { |
- int variable = builder.global.parameters[node]; |
- if (variable == null) return null; |
- return solver.getValueInferredForVariable(variable); |
- } |
-} |
- |
-enum BaseClassKind { |
- None, |
- Exact, |
- Subclass, |
- Subtype, |
-} |
- |
-/// An abstract value inferred by type propagation. |
-/// |
-/// Inferred values consist of two parts that each represent a set of values: |
-/// its base class and its bitmask. The InferredValue object represents the |
-/// intersection of these two value sets. |
-class InferredValue extends Node { |
- final Reference baseClassReference; |
- final BaseClassKind baseClassKind; |
- |
- /// A bitmask of the flags defined in [ValueBit], refining the set of values. |
- /// |
- /// These bits will always represent a subset of the values allowed by |
- /// the base class. For example, if the base class is "subclass of List", |
- /// the bitmask cannot contain [ValueBit.string], as this would contradict the |
- /// base class. |
- /// |
- /// The main use of the bitmask is to track nullability, and to preserve some |
- /// particularly important bits of information in case the no useful base |
- /// class could be found. |
- final int valueBits; |
- |
- InferredValue(Class baseClass, BaseClassKind baseClassKind, |
- [int valueBits = ValueBit.all]) |
- : this.byReference(baseClass?.reference, baseClassKind, valueBits); |
- |
- InferredValue.byReference( |
- this.baseClassReference, this.baseClassKind, this.valueBits) { |
- assert(baseClass != null || baseClassKind == BaseClassKind.None); |
- assert(baseClass == null || baseClassKind != BaseClassKind.None); |
- } |
- |
- Class get baseClass => baseClassReference?.asClass; |
- |
- InferredValue withBitmask(int newBitmask) { |
- if (newBitmask == valueBits) return this; |
- return new InferredValue(this.baseClass, this.baseClassKind, newBitmask); |
- } |
- |
- static final InferredValue nothing = |
- new InferredValue(null, BaseClassKind.None, 0); |
- |
- bool get canBeNull => valueBits & ValueBit.null_ != 0; |
- bool get isAlwaysNull => baseClass == null && valueBits == ValueBit.null_; |
- |
- /// True if this represents no value at all. |
- /// |
- /// When this value is inferred for a variable, it implies that the |
- /// surrounding code is unreachable. |
- bool get isNothing => baseClass == null && valueBits == 0; |
- |
- /// True if the value must be null or a concrete instance of [baseClass]. |
- bool get isExact => baseClassKind == BaseClassKind.Exact; |
- |
- /// True if the value must be null or a subclass of [baseClass]. |
- bool get isSubclass => baseClassKind == BaseClassKind.Subclass; |
- |
- /// True if the value must be null or a subtype of [baseClass]. |
- bool get isSubtype => baseClassKind == BaseClassKind.Subtype; |
- |
- accept(Visitor v) => v.visitInferredValue(this); |
- |
- visitChildren(Visitor v) { |
- baseClass?.acceptReference(v); |
- } |
-} |
- |
-/// Defines bits representing value sets for use in [InferredValue.valueBits]. |
-/// |
-/// The bitmask defines a partition of the entire value space, so every concrete |
-/// value corresponds to exactly one value bit. |
-class ValueBit { |
- static const int null_ = 1 << 0; |
- static const int integer = 1 << 1; |
- static const int double_ = 1 << 2; |
- static const int string = 1 << 3; |
- |
- /// Bit representing all values other than those above. |
- /// |
- /// This bit ensures that the bitmask represents a complete partition of the |
- /// value space, allowing clients to reason about it as a closed union type. |
- /// |
- /// For example, if [integer] and [string] are the only bits that are set, |
- /// it is safe to conclude that the value can *only* be an integer or string |
- /// as all other potential values are ruled out. |
- static const int other = 1 << 4; |
- |
- static const numberOfBits = 5; |
- static const int all = (1 << numberOfBits) - 1; |
- |
- static const Map<int, String> names = const <int, String>{ |
- null_: 'null', |
- integer: 'int', |
- double_: 'double', |
- string: 'string', |
- other: 'other', |
- }; |
- |
- static String format(int bitmask) { |
- if (bitmask == all) return '{*}'; |
- List<String> list = <String>[]; |
- for (int i = 0; i < numberOfBits; ++i) { |
- if (bitmask & (1 << i) != 0) { |
- list.add(names[1 << i] ?? '?'); |
- } |
- } |
- return '{${list.join(",")}}'; |
- } |
-} |