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

Unified Diff: sdk/lib/_internal/compiler/implementation/inferrer/container_tracer.dart

Issue 24994003: Re-apply "Move the container tracer to the call graph inferrer.". (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 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: sdk/lib/_internal/compiler/implementation/inferrer/container_tracer.dart
===================================================================
--- sdk/lib/_internal/compiler/implementation/inferrer/container_tracer.dart (revision 27995)
+++ sdk/lib/_internal/compiler/implementation/inferrer/container_tracer.dart (working copy)
@@ -2,18 +2,8 @@
// 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 container_tracer;
+part of type_graph_inferrer;
-import '../dart2jslib.dart' hide Selector, TypedSelector;
-import '../elements/elements.dart';
-import '../tree/tree.dart';
-import '../universe/universe.dart';
-import '../util/util.dart' show Link;
-import 'simple_types_inferrer.dart'
- show InferrerEngine, InferrerVisitor, LocalsHandler, TypeMaskSystem;
-import '../types/types.dart';
-import 'inferrer_visitor.dart';
-
/**
* A set of selector names that [List] implements, that we know do not
* change the element type of the list, or let the list escape to code
@@ -136,672 +126,154 @@
bool _VERBOSE = false;
-class InferrerEngineForContainerTracer
- implements MinimalInferrerEngine<TypeMask> {
+class ContainerTracerVisitor implements TypeInformationVisitor {
+ final ContainerTypeInformation container;
+ final TypeGraphInferrerEngine inferrer;
final Compiler compiler;
- InferrerEngineForContainerTracer(this.compiler);
+ // The set of [TypeInformation] where the traced container could
+ // flow in, and operations done on them.
+ final Set<TypeInformation> allUsers = new Set<TypeInformation>();
- TypeMask typeOfElement(Element element) {
- return compiler.typesTask.getGuaranteedTypeOfElement(element);
- }
+ // The list of found assignments to the container.
+ final List<TypeInformation> assignments = <TypeInformation>[];
- TypeMask returnTypeOfElement(Element element) {
- return compiler.typesTask.getGuaranteedReturnTypeOfElement(element);
- }
+ bool enableLengthTracking = true;
+ bool continueAnalyzing = true;
- TypeMask returnTypeOfSelector(Selector selector) {
- return compiler.typesTask.getGuaranteedTypeOfSelector(selector);
- }
-
- TypeMask typeOfNode(Node node) {
- return compiler.typesTask.getGuaranteedTypeOfNode(null, node);
- }
-
- Iterable<Element> getCallersOf(Element element) {
- return compiler.typesTask.typesInferrer.getCallersOf(element);
- }
-
- void recordTypeOfNonFinalField(Node node,
- Element field,
- TypeMask type) {}
-}
-
-/**
- * Global analysis phase that traces container instantiations in order to
- * find their element type.
- */
-class ContainerTracer extends CompilerTask {
- ContainerTracer(Compiler compiler) : super(compiler);
-
- String get name => 'List tracer';
-
- bool analyze() {
- measure(() {
- if (compiler.disableTypeInference) return;
- TypesInferrer inferrer = compiler.typesTask.typesInferrer;
- InferrerEngineForContainerTracer engine =
- new InferrerEngineForContainerTracer(compiler);
-
- // Walk over all created [ContainerTypeMask].
- inferrer.containerTypes.forEach((ContainerTypeMask mask) {
- // The element type has already been set for const containers.
- if (mask.elementType != null) return;
- new TracerForConcreteContainer(mask, this, compiler, engine).run();
- });
- });
- }
-}
-
-/**
- * A tracer for a specific container.
- */
-class TracerForConcreteContainer {
- final Compiler compiler;
- final ContainerTracer tracer;
- final InferrerEngineForContainerTracer inferrer;
- final ContainerTypeMask mask;
-
- final Node analyzedNode;
- final Element startElement;
-
- final List<Element> workList = <Element>[];
-
- /**
- * A set of elements where this list might escape.
- */
- final Set<Element> escapingElements = new Set<Element>();
-
- /**
- * A set of selectors that both use and update the list, for example
- * [: list[0]++; :] or [: list[0] |= 42; :].
- */
- final Set<Selector> constraints = new Set<Selector>();
-
- /**
- * A cache of setters that were already seen. Caching these
- * selectors avoid the filtering done in [addSettersToAnalysis].
- */
- final Set<Selector> seenSetterSelectors = new Set<Selector>();
-
static const int MAX_ANALYSIS_COUNT = 11;
+ final Set<Element> analyzedElements = new Set<Element>();
- TypeMask potentialType;
- int potentialLength;
- bool isLengthTrackingDisabled = false;
- bool continueAnalyzing = true;
+ ContainerTracerVisitor(this.container, inferrer)
+ : this.inferrer = inferrer, this.compiler = inferrer.compiler;
- TracerForConcreteContainer(ContainerTypeMask mask,
- this.tracer,
- this.compiler,
- this.inferrer)
- : analyzedNode = mask.allocationNode,
- startElement = mask.allocationElement,
- this.mask = mask;
-
void run() {
- int analysisCount = 0;
- workList.add(startElement);
+ // Add the assignments found at allocation site.
+ assignments.addAll(container.elementType.assignments);
+
+ // Collect the [TypeInformation] where the container can flow in,
+ // as well as the operations done on all these [TypeInformation]s.
+ List<TypeInformation> workList = <TypeInformation>[];
+ allUsers.add(container);
+ workList.add(container);
while (!workList.isEmpty) {
- if (workList.length + analysisCount > MAX_ANALYSIS_COUNT) {
+ TypeInformation user = workList.removeLast();
+ user.users.forEach((TypeInformation info) {
+ if (allUsers.contains(info)) return;
+ allUsers.add(info);
+ analyzedElements.add(info.owner);
+ if (info.reachedBy(user, inferrer)) {
+ workList.add(info);
+ }
+ });
+ if (analyzedElements.length > MAX_ANALYSIS_COUNT) {
bailout('Too many users');
break;
}
- Element currentElement = workList.removeLast().implementation;
- new ContainerTracerVisitor(currentElement, this).run();
- if (!continueAnalyzing) break;
- analysisCount++;
}
- if (!continueAnalyzing) {
- if (mask.forwardTo == compiler.typesTask.fixedListType) {
- mask.length = potentialLength;
+ if (continueAnalyzing) {
+ for (TypeInformation info in allUsers) {
+ info.accept(this);
+ if (!continueAnalyzing) break;
}
- mask.elementType = compiler.typesTask.dynamicType;
- return;
}
- // [potentialType] can be null if we did not find any instruction
- // that adds elements to the list.
- if (potentialType == null) {
- if (_VERBOSE) {
- print('Found empty type for $analyzedNode $startElement');
- }
- mask.elementType = new TypeMask.nonNullEmpty();
- return;
+ ContainerTypeMask mask = container.type;
+ if (!enableLengthTracking
+ && (mask.forwardTo != compiler.typesTask.fixedListType)) {
+ mask.length = null;
}
- // Walk over the found constraints and update the type according
- // to the selectors of these constraints.
- for (Selector constraint in constraints) {
- assert(constraint.isOperator());
- constraint = new TypedSelector(potentialType, constraint);
- potentialType = potentialType.union(
- inferrer.returnTypeOfSelector(constraint), compiler);
- }
+ TypeMask result = continueAnalyzing
+ ? inferrer.types.computeTypeMask(assignments)
+ : inferrer.types.dynamicType.type;
+
+ mask.elementType = result;
if (_VERBOSE) {
- print('$potentialType and $potentialLength '
- 'for $analyzedNode $startElement');
+ print('$result and ${mask.length} '
+ 'for ${mask.allocationNode} ${mask.allocationElement}');
}
- mask.elementType = potentialType;
- mask.length = potentialLength;
}
- void disableLengthTracking() {
- if (mask.forwardTo == compiler.typesTask.fixedListType) {
- // Bogus update to a fixed list.
- return;
- }
- isLengthTrackingDisabled = true;
- potentialLength = null;
- }
-
- void setPotentialLength(int value) {
- if (isLengthTrackingDisabled) return;
- potentialLength = value;
- }
-
- void unionPotentialTypeWith(TypeMask newType) {
- assert(newType != null);
- potentialType = potentialType == null
- ? newType
- : newType.union(potentialType, compiler);
- if (potentialType == compiler.typesTask.dynamicType) {
- bailout('Moved to dynamic');
- }
- }
-
- void addEscapingElement(element) {
- element = element.implementation;
- if (escapingElements.contains(element)) return;
- escapingElements.add(element);
- if (element.isField() || element.isGetter() || element.isFunction()) {
- for (Element e in inferrer.getCallersOf(element)) {
- addElementToAnalysis(e);
- }
- } else if (element.isParameter()) {
- addElementToAnalysis(element.enclosingElement);
- } else if (element.isFieldParameter()) {
- addEscapingElement(element.fieldElement);
- }
- }
-
- void addSettersToAnalysis(Selector selector) {
- assert(selector.isSetter());
- if (seenSetterSelectors.contains(selector)) return;
- seenSetterSelectors.add(selector);
- for (var e in compiler.world.allFunctions.filter(selector)) {
- e = e.implementation;
- if (e.isField()) {
- addEscapingElement(e);
- } else {
- FunctionSignature signature = e.computeSignature(compiler);
- signature.forEachRequiredParameter((Element e) {
- addEscapingElement(e);
- });
- }
- }
- }
-
- void addElementToAnalysis(Element element) {
- workList.add(element);
- }
-
- TypeMask bailout(String reason) {
+ void bailout(String reason) {
if (_VERBOSE) {
- print('Bailout on $analyzedNode $startElement because of $reason');
+ ContainerTypeMask mask = container.type;
+ print('Bailing out on ${mask.allocationNode} ${mask.allocationElement} '
+ 'because: $reason');
}
continueAnalyzing = false;
- return compiler.typesTask.dynamicType;
+ enableLengthTracking = false;
}
- bool couldBeTheList(resolved) {
- if (resolved is Selector) {
- return escapingElements.any((e) {
- return e.isInstanceMember() && resolved.applies(e, compiler);
- });
- } else if (resolved is Node) {
- return analyzedNode == resolved;
- } else {
- assert(resolved is Element);
- return escapingElements.contains(resolved);
- }
- }
+ visitNarrowTypeInformation(NarrowTypeInformation info) {}
+ visitPhiElementTypeInformation(PhiElementTypeInformation info) {}
+ visitElementInContainerTypeInformation(
+ ElementInContainerTypeInformation info) {}
+ visitContainerTypeInformation(ContainerTypeInformation info) {}
+ visitConcreteTypeInformation(ConcreteTypeInformation info) {}
- void recordConstraint(Selector selector) {
- constraints.add(selector);
+ visitClosureCallSiteTypeInformation(ClosureCallSiteTypeInformation info) {
+ bailout('Passed to a closure');
}
-}
-class ContainerTracerVisitor
- extends InferrerVisitor<TypeMask, InferrerEngineForContainerTracer> {
- final Element analyzedElement;
- final TracerForConcreteContainer tracer;
- final bool visitingClosure;
-
- ContainerTracerVisitor(element, tracer, [LocalsHandler<TypeMask> locals])
- : super(element, tracer.inferrer, new TypeMaskSystem(tracer.compiler),
- tracer.compiler, locals),
- this.analyzedElement = element,
- this.tracer = tracer,
- visitingClosure = locals != null;
-
- bool escaping = false;
- bool visitingInitializers = false;
-
- void run() {
- compiler.withCurrentElement(analyzedElement, () {
- visit(analyzedElement.parseNode(compiler));
- });
- }
-
- /**
- * Executes [f] and returns whether it triggered the list to escape.
- */
- bool visitAndCatchEscaping(Function f) {
- bool oldEscaping = escaping;
- escaping = false;
- f();
- bool foundEscaping = escaping;
- escaping = oldEscaping;
- return foundEscaping;
- }
-
- /**
- * Visits the [arguments] of [callee], and records the parameters
- * that could hold the container as escaping.
- *
- * Returns whether the container escaped.
- */
- bool visitArguments(Link<Node> arguments, /* Element or Selector */ callee) {
- List<int> indices = [];
- int index = 0;
- for (Node node in arguments) {
- if (visitAndCatchEscaping(() { visit(node); })) {
- indices.add(index);
- }
- index++;
+ visitStaticCallSiteTypeInformation(StaticCallSiteTypeInformation info) {
+ analyzedElements.add(info.caller);
+ Element called = info.calledElement;
+ if (called.isForeign(compiler) && called.name == const SourceString('JS')) {
+ bailout('Used in JS ${info.call}');
}
- if (!indices.isEmpty) {
- Iterable<Element> callees;
- if (callee is Element) {
- // No need to go further, we know the call will throw.
- if (callee.isErroneous()) return false;
- callees = [callee];
- } else {
- assert(callee is Selector);
- callees = compiler.world.allFunctions.filter(callee);
- }
- for (var e in callees) {
- e = e.implementation;
- if (e.isField()) {
- tracer.bailout('Passed to a closure');
- break;
- }
- FunctionSignature signature = e.computeSignature(compiler);
- index = 0;
- int parameterIndex = 0;
- signature.forEachRequiredParameter((Element parameter) {
- if (index < indices.length && indices[index] == parameterIndex) {
- tracer.addEscapingElement(parameter);
- index++;
- }
- parameterIndex++;
- });
- if (index != indices.length) {
- tracer.bailout('Used in a named parameter or closure');
- }
- }
- return true;
- } else {
- return false;
- }
}
- TypeMask visitFunctionExpression(FunctionExpression node) {
- FunctionElement function = elements[node];
- if (function != analyzedElement) {
- // Visiting a closure.
- LocalsHandler closureLocals = new LocalsHandler<TypeMask>.from(
- locals, node, useOtherTryBlock: false);
- new ContainerTracerVisitor(function, tracer, closureLocals).run();
- return types.functionType;
- } else {
- // Visiting [analyzedElement].
- FunctionSignature signature = function.computeSignature(compiler);
- signature.forEachParameter((element) {
- locals.update(element, inferrer.typeOfElement(element), node);
- });
- visitingInitializers = true;
- visit(node.initializers);
- visitingInitializers = false;
- visit(node.body);
- return null;
- }
- }
-
- TypeMask visitLiteralList(LiteralList node) {
- if (node.isConst()) {
- return inferrer.typeOfNode(node);
- }
- if (tracer.couldBeTheList(node)) {
- escaping = true;
- int length = 0;
- for (Node element in node.elements.nodes) {
- tracer.unionPotentialTypeWith(visit(element));
- length++;
- }
- tracer.setPotentialLength(length);
- } else {
- node.visitChildren(this);
- }
- return types.growableListType;
- }
-
- TypeMask visitSendSet(SendSet node) {
- bool isReceiver = visitAndCatchEscaping(() {
- visit(node.receiver);
- });
- return handleSendSet(node, isReceiver);
- }
-
- TypeMask handleSendSet(SendSet node, bool isReceiver) {
- TypeMask rhsType;
- TypeMask indexType;
-
- Selector getterSelector =
- elements.getGetterSelectorInComplexSendSet(node);
- Selector operatorSelector =
- elements.getOperatorSelectorInComplexSendSet(node);
- Selector setterSelector = elements.getSelector(node);
-
- String op = node.assignmentOperator.source.stringValue;
- bool isIncrementOrDecrement = op == '++' || op == '--';
- bool isIndexEscaping = false;
- bool isValueEscaping = false;
- if (isIncrementOrDecrement) {
- rhsType = types.intType;
- if (node.isIndex) {
- isIndexEscaping = visitAndCatchEscaping(() {
- indexType = visit(node.arguments.head);
- });
- }
- } else if (node.isIndex) {
- isIndexEscaping = visitAndCatchEscaping(() {
- indexType = visit(node.arguments.head);
- });
- isValueEscaping = visitAndCatchEscaping(() {
- rhsType = visit(node.arguments.tail.head);
- });
- } else {
- isValueEscaping = visitAndCatchEscaping(() {
- rhsType = visit(node.arguments.head);
- });
- }
-
- Element element = elements[node];
-
- if (node.isIndex) {
- if (isReceiver) {
- if (op == '=') {
- tracer.unionPotentialTypeWith(rhsType);
- } else {
- tracer.recordConstraint(operatorSelector);
- }
- } else if (isIndexEscaping || isValueEscaping) {
- // If the index or value is escaping, iterate over all
- // potential targets, and mark their parameter as escaping.
- for (var e in compiler.world.allFunctions.filter(setterSelector)) {
- e = e.implementation;
- FunctionSignature signature = e.computeSignature(compiler);
- int index = 0;
- signature.forEachRequiredParameter((Element parameter) {
- if (index == 0 && isIndexEscaping) {
- tracer.addEscapingElement(parameter);
+ visitDynamicCallSiteTypeInformation(DynamicCallSiteTypeInformation info) {
+ Selector selector = info.selector;
+ String selectorName = selector.name.slowToString();
+ if (allUsers.contains(info.receiver)) {
+ if (!okSelectorsSet.contains(selectorName)) {
+ if (selector.isCall()) {
+ int positionalLength = info.arguments.positional.length;
+ if (selectorName == 'add') {
+ if (positionalLength == 1) {
+ assignments.add(info.arguments.positional[0]);
}
- if (index == 1 && isValueEscaping) {
- tracer.addEscapingElement(parameter);
+ } else if (selectorName == 'insert') {
+ if (positionalLength == 2) {
+ assignments.add(info.arguments.positional[1]);
}
- index++;
- });
+ } else {
+ bailout('Used in a not-ok selector');
+ return;
+ }
+ } else if (selector.isIndexSet()) {
+ assignments.add(info.arguments.positional[1]);
+ } else if (!selector.isIndex()) {
+ bailout('Used in a not-ok selector');
+ return;
}
}
- } else if (isReceiver) {
- if (setterSelector.name == const SourceString('length')) {
- tracer.disableLengthTracking();
- tracer.unionPotentialTypeWith(compiler.typesTask.nullType);
+ if (!doNotChangeLengthSelectorsSet.contains(selectorName)) {
+ enableLengthTracking = false;
}
- } else if (isValueEscaping) {
- if (element != null
- && element.isField()
- && setterSelector == null
- && !visitingInitializers) {
- // Initializer at declaration of a field.
- assert(analyzedElement.isField());
- tracer.addEscapingElement(analyzedElement);
- } else if (element != null
- && (!element.isInstanceMember() || visitingInitializers)) {
- // A local, a static element, or a field in an initializer.
- tracer.addEscapingElement(element);
- } else {
- tracer.addSettersToAnalysis(setterSelector);
+ if (selectorName == 'length' && selector.isSetter()) {
+ enableLengthTracking = false;
+ assignments.add(inferrer.types.nullType);
}
+ } else if (selector.isCall()
+ && !info.targets.every((element) => element.isFunction())) {
+ bailout('Passed to a closure');
+ return;
}
-
- TypeMask result;
- if (node.isPostfix) {
- // We don't check if [getterSelector] could be the container because
- // a list++ will always throw.
- result = inferrer.returnTypeOfSelector(getterSelector);
- } else if (op != '=') {
- // We don't check if [getterSelector] could be the container because
- // a list += 42 will always throw.
- result = inferrer.returnTypeOfSelector(operatorSelector);
- } else {
- if (isValueEscaping) {
- escaping = true;
- }
- result = rhsType;
- }
-
- if (Elements.isLocal(element)) {
- locals.update(element, result, node);
- }
-
- return result;
}
- TypeMask visitSuperSend(Send node) {
- Element element = elements[node];
- if (!node.isPropertyAccess) {
- visitArguments(node.arguments, element);
- }
-
- if (tracer.couldBeTheList(element)) {
- escaping = true;
- }
-
- if (element.isField()) {
- return inferrer.typeOfElement(element);
- } else if (element.isFunction()) {
- return inferrer.returnTypeOfElement(element);
- } else {
- return types.dynamicType;
- }
+ bool isClosure(Element element) {
+ if (!element.isFunction()) return false;
+ Element outermost = element.getOutermostEnclosingMemberOrTopLevel();
+ return outermost.declaration != element.declaration;
}
- TypeMask visitStaticSend(Send node) {
- Element element = elements[node];
-
- if (Elements.isGrowableListConstructorCall(element, node, compiler)) {
- visitArguments(node.arguments, element);
- if (tracer.couldBeTheList(node)) {
- escaping = true;
- }
- return inferrer.typeOfNode(node);
- } else if (Elements.isFixedListConstructorCall(element, node, compiler)) {
- visitArguments(node.arguments, element);
- if (tracer.couldBeTheList(node)) {
- tracer.unionPotentialTypeWith(types.nullType);
- escaping = true;
- LiteralInt length = node.arguments.head.asLiteralInt();
- if (length != null) {
- tracer.setPotentialLength(length.value);
- }
- }
- return inferrer.typeOfNode(node);
- } else if (Elements.isFilledListConstructorCall(element, node, compiler)) {
- if (tracer.couldBeTheList(node)) {
- escaping = true;
- visit(node.arguments.head);
- TypeMask fillWithType = visit(node.arguments.tail.head);
- tracer.unionPotentialTypeWith(fillWithType);
- LiteralInt length = node.arguments.head.asLiteralInt();
- if (length != null) {
- tracer.setPotentialLength(length.value);
- }
- } else {
- visitArguments(node.arguments, element);
- }
- return inferrer.typeOfNode(node);
+ visitElementTypeInformation(ElementTypeInformation info) {
+ if (isClosure(info.element)) {
+ bailout('Returned from a closure');
}
-
- bool isEscaping = visitArguments(node.arguments, element);
-
- if (element.isForeign(compiler)) {
- if (isEscaping) return tracer.bailout('Used in a JS');
- }
-
- if (tracer.couldBeTheList(element)) {
- escaping = true;
- }
-
- if (element.isFunction() || element.isConstructor()) {
- return inferrer.returnTypeOfElement(element);
- } else {
- // Closure call or unresolved.
- return types.dynamicType;
- }
}
-
- TypeMask visitGetterSend(Send node) {
- Element element = elements[node];
- Selector selector = elements.getSelector(node);
- if (Elements.isStaticOrTopLevelField(element)) {
- if (tracer.couldBeTheList(element)) {
- escaping = true;
- }
- return inferrer.typeOfElement(element);
- } else if (Elements.isInstanceSend(node, elements)) {
- return visitDynamicSend(node);
- } else if (Elements.isStaticOrTopLevelFunction(element)) {
- return types.functionType;
- } else if (Elements.isErroneousElement(element)) {
- return types.dynamicType;
- } else if (Elements.isLocal(element)) {
- if (tracer.couldBeTheList(element)) {
- escaping = true;
- }
- return locals.use(element);
- } else {
- node.visitChildren(this);
- return types.dynamicType;
- }
- }
-
- TypeMask visitClosureSend(Send node) {
- assert(node.receiver == null);
- visit(node.selector);
- bool isEscaping =
- visitArguments(node.arguments, elements.getSelector(node));
-
- if (isEscaping) return tracer.bailout('Passed to a closure');
- return types.dynamicType;
- }
-
- TypeMask visitDynamicSend(Send node) {
- bool isReceiver = visitAndCatchEscaping(() {
- visit(node.receiver);
- });
- return handleDynamicSend(node, isReceiver);
- }
-
- TypeMask handleDynamicSend(Send node, bool isReceiver) {
- Selector selector = elements.getSelector(node);
- String selectorName = selector.name.slowToString();
- if (isReceiver && !okSelectorsSet.contains(selectorName)) {
- if (selector.isCall()
- && (selectorName == 'add' || selectorName == 'insert')) {
- TypeMask argumentType;
- if (node.arguments.isEmpty
- || (selectorName == 'insert' && node.arguments.tail.isEmpty)) {
- return tracer.bailout('Invalid "add" or "insert" call on a list');
- }
- bool isEscaping = visitAndCatchEscaping(() {
- argumentType = visit(node.arguments.head);
- if (selectorName == 'insert') {
- argumentType = visit(node.arguments.tail.head);
- }
- });
- if (isEscaping) {
- return tracer.bailout('List containing itself');
- }
- tracer.unionPotentialTypeWith(argumentType);
- } else {
- return tracer.bailout('Send with the node as receiver $node');
- }
- } else if (!node.isPropertyAccess) {
- visitArguments(node.arguments, selector);
- }
- if (isReceiver && !doNotChangeLengthSelectorsSet.contains(selectorName)) {
- tracer.disableLengthTracking();
- }
- if (tracer.couldBeTheList(selector)) {
- escaping = true;
- }
- return inferrer.returnTypeOfSelector(selector);
- }
-
- TypeMask visitReturn(Return node) {
- if (node.expression == null) {
- return types.nullType;
- }
-
- TypeMask type;
- bool isEscaping = visitAndCatchEscaping(() {
- type = visit(node.expression);
- });
-
- if (isEscaping) {
- if (visitingClosure) {
- tracer.bailout('Return from closure');
- } else {
- tracer.addEscapingElement(analyzedElement);
- }
- }
- return type;
- }
-
- TypeMask visitForIn(ForIn node) {
- visit(node.expression);
- Selector iteratorSelector = elements.getIteratorSelector(node);
- Selector currentSelector = elements.getCurrentSelector(node);
-
- TypeMask iteratorType = inferrer.returnTypeOfSelector(iteratorSelector);
- TypeMask currentType = inferrer.returnTypeOfSelector(currentSelector);
-
- // We nullify the type in case there is no element in the
- // iterable.
- currentType = currentType.nullable();
-
- Node identifier = node.declaredIdentifier;
- Element element = elements[identifier];
- if (Elements.isLocal(element)) {
- locals.update(element, currentType, node);
- }
-
- return handleLoop(node, () {
- visit(node.body);
- });
- }
}

Powered by Google App Engine
This is Rietveld 408576698