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

Unified Diff: pkg/compiler/lib/src/types/types.dart

Issue 2468303003: dart2js: move type-mask intermediate data from tree-elements into the global (Closed)
Patch Set: bug fix: handle closures and constructor bodies Created 4 years, 1 month 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
« no previous file with comments | « pkg/compiler/lib/src/ssa/types.dart ('k') | tests/compiler/dart2js/concrete_type_inference_test.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/compiler/lib/src/types/types.dart
diff --git a/pkg/compiler/lib/src/types/types.dart b/pkg/compiler/lib/src/types/types.dart
index ad890dc6c79f6aaaee44a7880f2eb00d1abbeba8..82bed6faeda55b3eb75ed903fd817038a59330fc 100644
--- a/pkg/compiler/lib/src/types/types.dart
+++ b/pkg/compiler/lib/src/types/types.dart
@@ -4,17 +4,165 @@
library types;
+import '../closure.dart' show SynthesizedCallMethodElementX;
+import '../common.dart' show invariant;
import '../common/tasks.dart' show CompilerTask;
import '../compiler.dart' show Compiler;
import '../elements/elements.dart';
-import '../inferrer/type_graph_inferrer.dart' show TypeGraphInferrer;
+import '../inferrer/type_graph_inferrer.dart'
+ show TypeGraphInferrer, TypeInformationSystem;
import '../tree/tree.dart';
-import '../resolution/tree_elements.dart';
import '../universe/selector.dart' show Selector;
+import '../util/util.dart' show Maplet;
import 'masks.dart';
export 'masks.dart';
+/// Results about a single element (e.g. a method, parameter, or field)
+/// produced by the global type-inference algorithm.
+///
+/// All queries in this class may contain results that assume whole-program
+/// closed-world semantics. Any [TypeMask] for an element or node that we return
+/// was inferred to be a "guaranteed type", that means, it is a type that we
+/// can prove to be correct for all executions of the program. A trivial
+/// implementation would return false on all boolean properties (giving no
+/// guarantees) and the `subclass of Object or null` type mask for the type
+/// based queries (the runtime value could be anything).
+abstract class GlobalTypeInferenceElementResult {
+ /// Whether the method element associated with this result always throws.
+ bool get throwsAlways;
+
+ /// Whether the element associated with this result is only called once in one
+ /// location in the entire program.
+ bool get isCalledOnce;
+
+ /// The inferred type when this result belongs to a parameter or field
+ /// element, null otherwise.
+ TypeMask get type;
+
+ /// The inferred return type when this result belongs to a function element.
+ TypeMask get returnType;
+
+ /// Returns the type of a list allocation [node] (which can be a list
+ /// literal or a list new expression).
+ TypeMask typeOfNewList(Node node);
+
+ /// Returns the type of a send [node].
+ TypeMask typeOfSend(Node node);
+
+ /// Returns the type of the operator of a complex send-set [node], for
+ /// example, the type of `+` in `a += b`.
+ TypeMask typeOfGetter(SendSet node);
+
+ /// Returns the type of the getter in a complex send-set [node], for example,
+ /// the type of the `a.f` getter in `a.f += b`.
+ TypeMask typeOfOperator(SendSet node);
+
+ /// Returns the type of the iterator in a [loop].
+ TypeMask typeOfIterator(ForIn node);
+
+ /// Returns the type of the `moveNext` call of an iterator in a [loop].
+ TypeMask typeOfIteratorMoveNext(ForIn node);
+
+ /// Returns the type of the `current` getter of an iterator in a [loop].
+ TypeMask typeOfIteratorCurrent(ForIn node);
+}
+
+class GlobalTypeInferenceElementResultImpl
+ implements GlobalTypeInferenceElementResult {
+ // TODO(sigmund): delete, store data directly here.
+ final Element _owner;
+
+ // TODO(sigmund): split - stop using _data after inference is done.
+ final GlobalTypeInferenceElementData _data;
+
+ // TODO(sigmund): store relevant data & drop reference to inference engine.
+ final TypesInferrer _inferrer;
+ final bool _isJsInterop;
+ final TypeMask _dynamic;
+
+ GlobalTypeInferenceElementResultImpl(this._owner, this._data, this._inferrer,
+ this._isJsInterop, this._dynamic);
+
+ bool get isCalledOnce => _inferrer.isCalledOnce(_owner);
+
+ TypeMask get returnType =>
+ _isJsInterop ? _dynamic : _inferrer.getReturnTypeOfElement(_owner);
+
+ TypeMask get type =>
+ _isJsInterop ? _dynamic : _inferrer.getTypeOfElement(_owner);
+
+ bool get throwsAlways {
+ TypeMask mask = this.returnType;
+ // Always throws if the return type was inferred to be non-null empty.
+ return mask != null && mask.isEmpty;
+ }
+
+ TypeMask typeOfNewList(Node node) =>
+ _inferrer.getTypeForNewList(_owner, node);
+
+ TypeMask typeOfSend(Node node) => _data?.typeOfSend(node);
+ TypeMask typeOfGetter(SendSet node) => _data?.typeOfGetter(node);
+ TypeMask typeOfOperator(SendSet node) => _data?.typeOfOperator(node);
+ TypeMask typeOfIterator(ForIn node) => _data?.typeOfIterator(node);
+ TypeMask typeOfIteratorMoveNext(ForIn node) =>
+ _data?.typeOfIteratorMoveNext(node);
+ TypeMask typeOfIteratorCurrent(ForIn node) =>
+ _data?.typeOfIteratorCurrent(node);
+}
+
+/// Internal data used during type-inference to store intermediate results about
+/// a single element.
+class GlobalTypeInferenceElementData {
+ Map<Object, TypeMask> _typeMasks;
+
+ TypeMask _get(Object node) => _typeMasks != null ? _typeMasks[node] : null;
+ void _set(Object node, TypeMask mask) {
+ _typeMasks ??= new Maplet<Object, TypeMask>();
+ _typeMasks[node] = mask;
+ }
+
+ TypeMask typeOfSend(Node node) => _get(node);
+ TypeMask typeOfGetter(SendSet node) => _get(node.selector);
+ TypeMask typeOfOperator(SendSet node) => _get(node.assignmentOperator);
+
+ void setTypeMask(Node node, TypeMask mask) {
+ _set(node, mask);
+ }
+
+ void setGetterTypeMaskInComplexSendSet(SendSet node, TypeMask mask) {
+ _set(node.selector, mask);
+ }
+
+ void setOperatorTypeMaskInComplexSendSet(SendSet node, TypeMask mask) {
+ _set(node.assignmentOperator, mask);
+ }
+
+ // TODO(sigmund): clean up. We store data about 3 selectors for "for in"
+ // nodes: the iterator, move-next, and current element. Because our map keys
+ // are nodes, we need to fabricate different keys to keep these selectors
+ // separate. The current implementation does this by using
+ // children of the for-in node (these children were picked arbitrarily).
+
+ TypeMask typeOfIterator(ForIn node) => _get(node);
+
+ TypeMask typeOfIteratorMoveNext(ForIn node) => _get(node.forToken);
+
+ TypeMask typeOfIteratorCurrent(ForIn node) => _get(node.inToken);
+
+ void setIteratorTypeMask(ForIn node, TypeMask mask) {
+ _set(node, mask);
+ }
+
+ void setMoveNextTypeMask(ForIn node, TypeMask mask) {
+ _set(node.forToken, mask);
+ }
+
+ void setCurrentTypeMask(ForIn node, TypeMask mask) {
+ _set(node.inToken, mask);
+ }
+}
+
/// API to interact with the global type-inference engine.
abstract class TypesInferrer {
void analyzeMain(Element element);
@@ -35,91 +183,48 @@ abstract class TypesInferrer {
/// can prove to be correct for all executions of the program.
class GlobalTypeInferenceResults {
// TODO(sigmund): store relevant data & drop reference to inference engine.
- final TypesInferrer _inferrer;
+ final TypeGraphInferrer _inferrer;
final Compiler compiler;
final TypeMask dynamicType;
+ final Map<Element, GlobalTypeInferenceElementResult> _elementResults = {};
- GlobalTypeInferenceResults(this._inferrer, this.compiler, CommonMasks masks)
- : dynamicType = masks.dynamicType;
+ // TODO(sigmund,johnniwinther): compute result objects eagerly and make it an
+ // error to query for results that don't exist.
+ GlobalTypeInferenceElementResult resultOf(AstElement element) {
+ assert(invariant(element, !element.isGenerativeConstructorBody,
+ message: "unexpected input: ConstructorBodyElements are created"
+ " after global type inference, no data is avaiable for them."));
- /// Returns the type of a parameter or field [element], if any.
- TypeMask typeOf(Element element) {
- // TODO(24489): trust some JsInterop types.
- if (compiler.backend.isJsInterop(element)) return dynamicType;
- return _inferrer.getTypeOfElement(element);
+ // TODO(sigmund): store closure data directly in the closure element and
+ // not in the context of the enclosing method?
+ var key = (element is SynthesizedCallMethodElementX)
+ ? element.memberContext
+ : element;
+ return _elementResults.putIfAbsent(
+ element,
+ () => new GlobalTypeInferenceElementResultImpl(
+ element,
+ _inferrer.inferrer.inTreeData[key],
+ _inferrer,
+ compiler.backend.isJsInterop(element),
+ dynamicType));
}
- /// Returns the return type of a method or function [element].
- TypeMask returnTypeOf(Element element) {
- // TODO(24489): trust some JsInterop types.
- if (compiler.backend.isJsInterop(element)) return dynamicType;
- return _inferrer.getReturnTypeOfElement(element);
- }
+ GlobalTypeInferenceResults(this._inferrer, this.compiler, CommonMasks masks,
+ TypeInformationSystem types)
+ : dynamicType = masks.dynamicType;
/// Returns the type of a [selector] when applied to a receiver with the given
/// type [mask].
TypeMask typeOfSelector(Selector selector, TypeMask mask) =>
_inferrer.getTypeOfSelector(selector, mask);
- /// Returns whether the method [element] always throws.
- bool throwsAlways(Element element) {
- // We know the element always throws if the return type was inferred to be
- // non-null empty.
- TypeMask returnType = returnTypeOf(element);
- return returnType != null && returnType.isEmpty;
- }
-
- /// Returns whether [element] is only called once in the entire program.
- bool isCalledOnce(Element element) => _inferrer.isCalledOnce(element);
-
- // TODO(sigmund): introduce a new class [ElementInferenceResult] that can be
- // used to collect any information that is specific about the body within a
- // single element (basically everything below this line). We could consider
- // moving some of the functions above too, for example:
- // results.throwsAlways(element)
- // could become:
- // results[element].alwaysThrows;
- //
-
- /// Returns the type of a list allocation [node] occuring within [owner].
- ///
- /// [node] can be a list literal or a list new expression.
- TypeMask typeOfNewList(Element owner, Node node) =>
- _inferrer.getTypeForNewList(owner, node);
-
/// Returns whether a fixed-length constructor call goes through a growable
/// check.
+ // TODO(sigmund): move into the result of the element containing such
+ // constructor call.
bool isFixedArrayCheckedForGrowable(Node ctorCall) =>
_inferrer.isFixedArrayCheckedForGrowable(ctorCall);
-
- /// Returns the type of a send [node].
- TypeMask typeOfSend(
- Node node,
- // TODO(sigmund): move inference data out of TreeElements
- TreeElements elements) =>
- elements.getTypeMask(node);
-
- /// Returns the type of the operator of a complex send-set [node], for
- /// example, the type of `+` in `a += b`.
- TypeMask typeOfOperator(Send node, TreeElements elements) =>
- elements.getOperatorTypeMaskInComplexSendSet(node);
-
- /// Returns the type of the getter in a complex send-set [node], for example,
- /// the type of the `a.f` getter in `a.f += b`.
- TypeMask typeOfGetter(node, elements) =>
- elements.getGetterTypeMaskInComplexSendSet(node);
-
- /// Returns the type of the iterator in a [loop].
- TypeMask typeOfIterator(ForIn loop, elements) =>
- elements.getIteratorTypeMask(loop);
-
- /// Returns the type of the `moveNext` call of an iterator in a [loop].
- TypeMask typeOfIteratorMoveNext(ForIn loop, elements) =>
- elements.getMoveNextTypeMask(loop);
-
- /// Returns the type of the `current` getter of an iterator in a [loop].
- TypeMask typeOfIteratorCurrent(ForIn node, elements) =>
- elements.getCurrentTypeMask(node);
}
/// Global analysis that infers concrete types.
@@ -128,7 +233,7 @@ class GlobalTypeInferenceTask extends CompilerTask {
final String name = 'Type inference';
final Compiler compiler;
- TypesInferrer typesInferrer;
+ TypeGraphInferrer typesInferrer;
CommonMasks masks;
GlobalTypeInferenceResults results;
@@ -144,7 +249,8 @@ class GlobalTypeInferenceTask extends CompilerTask {
measure(() {
typesInferrer.analyzeMain(mainElement);
typesInferrer.clear();
- results = new GlobalTypeInferenceResults(typesInferrer, compiler, masks);
+ results = new GlobalTypeInferenceResults(
+ typesInferrer, compiler, masks, typesInferrer.inferrer.types);
});
}
}
« no previous file with comments | « pkg/compiler/lib/src/ssa/types.dart ('k') | tests/compiler/dart2js/concrete_type_inference_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698