Add LocalState to KernelTypeGraphBuilder
Move LocalsHandler.seenBreakOrContinue/seenReturnOrThrow/_tryBlock to LocalState
Move KernelTypeGraphBuilder._locals and KernelTypeGraphBuilder._fieldScope from visitor to LocalState
Change-Id: I712558ab3d18c6196fb5b96a4f8084d44848b83b
Reviewed-on: https://dart-review.googlesource.com/c/85444
Reviewed-by: Sigmund Cherem <sigmund@google.com>
Commit-Queue: Johnni Winther <johnniwinther@google.com>
diff --git a/pkg/compiler/lib/src/inferrer/builder_kernel.dart b/pkg/compiler/lib/src/inferrer/builder_kernel.dart
index 3009a68..8a7dfdd 100644
--- a/pkg/compiler/lib/src/inferrer/builder_kernel.dart
+++ b/pkg/compiler/lib/src/inferrer/builder_kernel.dart
@@ -48,13 +48,12 @@
final GlobalTypeInferenceElementData _memberData;
final bool _inGenerativeConstructor;
- LocalsHandler _locals;
- FieldInitializationScope _fieldScope;
+ LocalState _state;
final SideEffectsBuilder _sideEffectsBuilder;
- final Map<JumpTarget, List<LocalsHandler>> _breaksFor =
- <JumpTarget, List<LocalsHandler>>{};
- final Map<JumpTarget, List<LocalsHandler>> _continuesFor =
- <JumpTarget, List<LocalsHandler>>{};
+ final Map<JumpTarget, List<LocalState>> _breaksFor =
+ <JumpTarget, List<LocalState>>{};
+ final Map<JumpTarget, List<LocalState>> _continuesFor =
+ <JumpTarget, List<LocalState>>{};
TypeInformation _returnType;
final Set<Local> _capturedVariables = new Set<Local>();
final Map<Local, FieldEntity> _capturedAndBoxed;
@@ -71,9 +70,7 @@
KernelTypeGraphBuilder(this._options, this._closedWorld, this._inferrer,
this._analyzedMember, this._analyzedNode, this._localsMap,
- [this._locals,
- this._fieldScope,
- Map<Local, FieldEntity> capturedAndBoxed])
+ [this._state, Map<Local, FieldEntity> capturedAndBoxed])
: this._types = _inferrer.types,
this._memberData = _inferrer.dataOfMember(_analyzedMember),
// TODO(johnniwinther): Should side effects also be tracked for field
@@ -86,11 +83,10 @@
this._capturedAndBoxed = capturedAndBoxed != null
? new Map<Local, FieldEntity>.from(capturedAndBoxed)
: <Local, FieldEntity>{} {
- if (_locals != null) return;
+ if (_state != null) return;
- _fieldScope =
- _inGenerativeConstructor ? new FieldInitializationScope() : null;
- _locals = new LocalsHandler(_analyzedNode);
+ _state = new LocalState.initial(_analyzedNode,
+ inGenerativeConstructor: _inGenerativeConstructor);
}
JsToElementMap get _elementMap => _closedWorld.elementMap;
@@ -101,16 +97,6 @@
bool get inLoop => _loopLevel > 0;
- bool get _isThisExposed {
- return _inGenerativeConstructor ? _fieldScope.isThisExposed : true;
- }
-
- void _markThisAsExposed() {
- if (_inGenerativeConstructor) {
- _fieldScope.isThisExposed = true;
- }
- }
-
/// Returns `true` if [member] is defined in a subclass of the current this
/// type.
bool _isInClassOrSubclass(MemberEntity member) {
@@ -129,14 +115,14 @@
/// field is considered to have been read before initialization and the field
/// is assumed to be potentially `null`.
void _checkIfExposesThis(Selector selector, AbstractValue mask) {
- if (_isThisExposed) {
+ if (_state.isThisExposed) {
// We already consider `this` to have been exposed.
return;
}
if (_inferrer.closedWorld.includesClosureCall(selector, mask)) {
// TODO(ngeoffray): We could do better here if we knew what we
// are calling does not expose this.
- _markThisAsExposed();
+ _state.markThisAsExposed();
} else {
_inferrer.forEachElementMatching(selector, mask, (MemberEntity element) {
if (element != null && element.isField) {
@@ -144,7 +130,7 @@
if (!selector.isSetter &&
_isInClassOrSubclass(field) &&
field.isAssignable &&
- _fieldScope.readField(field) == null &&
+ _state.readField(field) == null &&
getFieldInitializer(_elementMap, field) == null) {
// If the field is being used before this constructor
// actually had a chance to initialize it, say it can be
@@ -156,7 +142,7 @@
}
// TODO(ngeoffray): We could do better here if we knew what we
// are calling does not expose this.
- _markThisAsExposed();
+ _state.markThisAsExposed();
return false;
});
}
@@ -199,12 +185,6 @@
_inferrer.addReturnTypeForMethod(analyzedMethod, _returnType, type);
}
- void initializationIsIndefinite() {
- if (_inGenerativeConstructor) {
- _fieldScope.isIndefinite = true;
- }
- }
-
TypeInformation _thisType;
TypeInformation get thisType {
if (_thisType != null) return _thisType;
@@ -232,7 +212,7 @@
void handleParameter(ir.VariableDeclaration node, {bool isOptional}) {
Local local = _localsMap.getLocalVariable(node);
DartType type = _localsMap.getLocalType(_elementMap, local);
- _locals.update(_inferrer, _capturedAndBoxed, local,
+ _state.updateLocal(_inferrer, _capturedAndBoxed, local,
_inferrer.typeOfParameter(local), node, type);
if (isOptional) {
TypeInformation type;
@@ -260,7 +240,7 @@
_elementMap.elementEnvironment.forEachLocalClassMember(cls,
(MemberEntity member) {
if (member.isField && member.isInstanceMember && member.isAssignable) {
- TypeInformation type = _fieldScope.readField(member);
+ TypeInformation type = _state.readField(member);
MemberDefinition definition = _elementMap.getMemberDefinition(member);
assert(definition.kind == MemberKind.regular);
ir.Field node = definition.node;
@@ -272,7 +252,7 @@
}
});
}
- _inferrer.recordExposesThis(_analyzedMember, _isThisExposed);
+ _inferrer.recordExposesThis(_analyzedMember, _state.isThisExposed);
if (cls.isAbstract) {
if (_closedWorld.classHierarchy.isInstantiated(cls)) {
@@ -294,7 +274,7 @@
visitFieldInitializer(ir.FieldInitializer node) {
TypeInformation rhsType = visit(node.value);
FieldEntity field = _elementMap.getField(node.field);
- _fieldScope.updateField(field, rhsType);
+ _state.updateField(field, rhsType);
_inferrer.recordTypeOfField(field, rhsType);
return null;
}
@@ -311,7 +291,7 @@
_inferrer.analyze(constructor);
if (_inferrer.checkIfExposesThis(constructor)) {
- _markThisAsExposed();
+ _state.markThisAsExposed();
}
return null;
}
@@ -328,7 +308,7 @@
_inferrer.analyze(constructor);
if (_inferrer.checkIfExposesThis(constructor)) {
- _markThisAsExposed();
+ _state.markThisAsExposed();
}
return null;
}
@@ -366,10 +346,10 @@
case ir.AsyncMarker.Sync:
if (_returnType == null) {
// No return in the body.
- _returnType = _locals.seenReturnOrThrow
+ _returnType = _state.seenReturnOrThrow
? _types.nonNullEmpty() // Body always throws.
: _types.nullType;
- } else if (!_locals.seenReturnOrThrow) {
+ } else if (!_state.seenReturnOrThrow) {
// We haven'TypeInformation seen returns on all branches. So the
// method may also return null.
recordReturnType(_types.nullType);
@@ -429,7 +409,7 @@
visitBlock(ir.Block block) {
for (ir.Statement statement in block.statements) {
visit(statement);
- if (_locals.aborts) break;
+ if (_state.aborts) break;
}
return null;
}
@@ -458,39 +438,33 @@
List<IsCheck> negativeTests = <IsCheck>[];
bool simpleCondition =
handleCondition(node.condition, positiveTests, negativeTests);
- LocalsHandler localsBefore = _locals;
- FieldInitializationScope fieldScopeBefore = _fieldScope;
+ LocalState stateBefore = _state;
- _locals = new LocalsHandler.from(localsBefore, node);
+ _state = new LocalState.childPath(stateBefore, node);
_updateIsChecks(positiveTests, negativeTests);
- LocalsHandler localsAfterCondition = _locals;
- FieldInitializationScope fieldScopeAfterThen = _fieldScope;
+ LocalState stateAfterCondition = _state;
- _locals = new LocalsHandler.from(localsBefore, node);
- _fieldScope = new FieldInitializationScope.from(fieldScopeBefore);
+ _state = new LocalState.childPath(stateBefore, node);
if (simpleCondition) _updateIsChecks(negativeTests, positiveTests);
visit(node.message);
- LocalsHandler localsAfterMessage = _locals;
- FieldInitializationScope fieldScopeAfterMessage = _fieldScope;
- localsAfterMessage.seenReturnOrThrow = true;
- _locals = localsBefore.mergeDiamondFlow(
- _inferrer, localsAfterCondition, localsAfterMessage);
- _fieldScope = fieldScopeBefore?.mergeDiamondFlow(
- _inferrer, fieldScopeAfterThen, fieldScopeAfterMessage);
+ LocalState stateAfterMessage = _state;
+ stateAfterMessage.seenReturnOrThrow = true;
+ _state = stateBefore.mergeDiamondFlow(
+ _inferrer, stateAfterCondition, stateAfterMessage);
return null;
}
@override
visitBreakStatement(ir.BreakStatement node) {
JumpTarget target = _localsMap.getJumpTargetForBreak(node);
- _locals.seenBreakOrContinue = true;
+ _state.seenBreakOrContinue = true;
// Do a deep-copy of the locals, because the code following the
// break will change them.
if (_localsMap.generateContinueForBreak(node)) {
- _continuesFor[target].add(new LocalsHandler.deepCopyOf(_locals));
+ _continuesFor[target].add(new LocalState.deepCopyOf(_state));
} else {
- _breaksFor[target].add(new LocalsHandler.deepCopyOf(_locals));
+ _breaksFor[target].add(new LocalState.deepCopyOf(_state));
}
return null;
}
@@ -505,7 +479,7 @@
JumpTarget jumpTarget = _localsMap.getJumpTargetForLabel(node);
_setupBreaksAndContinues(jumpTarget);
visit(body);
- _locals.mergeAfterBreaks(_inferrer, _getBreaks(jumpTarget));
+ _state.mergeAfterBreaks(_inferrer, _getBreaks(jumpTarget));
_clearBreaksAndContinues(jumpTarget);
}
return null;
@@ -533,43 +507,38 @@
// visit all cases and update [locals] until we have reached a
// fixed point.
bool changed;
- _locals.startLoop(_inferrer, node);
+ _state.startLoop(_inferrer, node);
do {
changed = false;
for (ir.SwitchCase switchCase in node.cases) {
- LocalsHandler localsBeforeCase = _locals;
- FieldInitializationScope fieldScopeBeforeCase = _fieldScope;
- _locals = new LocalsHandler.from(localsBeforeCase, switchCase);
- _fieldScope = new FieldInitializationScope.from(fieldScopeBeforeCase);
+ LocalState stateBeforeCase = _state;
+ _state = new LocalState.childPath(stateBeforeCase, switchCase);
visit(switchCase);
- LocalsHandler localsAfterCase = _locals;
- changed = localsBeforeCase.mergeAll(_inferrer, [localsAfterCase]) ||
- changed;
- _locals = localsBeforeCase;
- _fieldScope = fieldScopeBeforeCase;
+ LocalState stateAfterCase = _state;
+ changed =
+ stateBeforeCase.mergeAll(_inferrer, [stateAfterCase]) || changed;
+ _state = stateBeforeCase;
}
} while (changed);
- _locals.endLoop(_inferrer, node);
+ _state.endLoop(_inferrer, node);
continueTargets.forEach(_clearBreaksAndContinues);
} else {
- LocalsHandler localsBeforeCase = _locals;
- FieldInitializationScope fieldScopeBeforeCase = _fieldScope;
- List<LocalsHandler> localsToMerge = <LocalsHandler>[];
+ LocalState stateBeforeCase = _state;
+ List<LocalState> statesToMerge = <LocalState>[];
bool hasDefaultCase = false;
for (ir.SwitchCase switchCase in node.cases) {
if (switchCase.isDefault) {
hasDefaultCase = true;
}
- _locals = new LocalsHandler.from(localsBeforeCase, switchCase);
+ _state = new LocalState.childPath(stateBeforeCase, switchCase);
visit(switchCase);
- localsToMerge.add(_locals);
+ statesToMerge.add(_state);
}
- localsBeforeCase.mergeAfterBreaks(_inferrer, localsToMerge,
+ stateBeforeCase.mergeAfterBreaks(_inferrer, statesToMerge,
keepOwnLocals: !hasDefaultCase);
- _locals = localsBeforeCase;
- _fieldScope = fieldScopeBeforeCase;
+ _state = stateBeforeCase;
}
_clearBreaksAndContinues(jumpTarget);
return null;
@@ -584,10 +553,10 @@
@override
visitContinueSwitchStatement(ir.ContinueSwitchStatement node) {
JumpTarget target = _localsMap.getJumpTargetForContinueSwitch(node);
- _locals.seenBreakOrContinue = true;
+ _state.seenBreakOrContinue = true;
// Do a deep-copy of the locals, because the code following the
// break will change them.
- _continuesFor[target].add(new LocalsHandler.deepCopyOf(_locals));
+ _continuesFor[target].add(new LocalState.deepCopyOf(_state));
return null;
}
@@ -637,8 +606,8 @@
TypeInformation visitReturnStatement(ir.ReturnStatement node) {
ir.Node expression = node.expression;
recordReturnType(expression == null ? _types.nullType : visit(expression));
- _locals.seenReturnOrThrow = true;
- initializationIsIndefinite();
+ _state.seenReturnOrThrow = true;
+ _state.markInitializationAsIndefinite();
return null;
}
@@ -706,14 +675,14 @@
Local local = _localsMap.getLocalVariable(node);
DartType type = _localsMap.getLocalType(_elementMap, local);
if (node.initializer == null) {
- _locals.update(
+ _state.updateLocal(
_inferrer, _capturedAndBoxed, local, _types.nullType, node, type);
} else {
- _locals.update(_inferrer, _capturedAndBoxed, local,
+ _state.updateLocal(_inferrer, _capturedAndBoxed, local,
visit(node.initializer), node, type);
}
if (node.initializer is ir.ThisExpression) {
- _markThisAsExposed();
+ _state.markThisAsExposed();
}
return null;
}
@@ -721,7 +690,8 @@
@override
TypeInformation visitVariableGet(ir.VariableGet node) {
Local local = _localsMap.getLocalVariable(node.variable);
- TypeInformation type = _locals.use(_inferrer, _capturedAndBoxed, local);
+ TypeInformation type =
+ _state.readLocal(_inferrer, _capturedAndBoxed, local);
assert(type != null, "Missing type information for $local.");
return type;
}
@@ -730,11 +700,12 @@
TypeInformation visitVariableSet(ir.VariableSet node) {
TypeInformation rhsType = visit(node.value);
if (node.value is ir.ThisExpression) {
- _markThisAsExposed();
+ _state.markThisAsExposed();
}
Local local = _localsMap.getLocalVariable(node.variable);
DartType type = _localsMap.getLocalType(_elementMap, local);
- _locals.update(_inferrer, _capturedAndBoxed, local, rhsType, node, type);
+ _state.updateLocal(
+ _inferrer, _capturedAndBoxed, local, rhsType, node, type);
return rhsType;
}
@@ -745,7 +716,7 @@
// TODO(ngeoffray): We could do better here if we knew what we
// are calling does not expose this.
if (argument is ir.ThisExpression) {
- _markThisAsExposed();
+ _state.markThisAsExposed();
}
positional.add(visit(argument));
}
@@ -755,7 +726,7 @@
// TODO(ngeoffray): We could do better here if we knew what we
// are calling does not expose this.
if (value is ir.ThisExpression) {
- _markThisAsExposed();
+ _state.markThisAsExposed();
}
named[argument.name] = visit(value);
}
@@ -846,7 +817,7 @@
TypeInformation refinedType = _types
.refineReceiver(selector, mask, receiverType, isConditional: false);
DartType type = _localsMap.getLocalType(_elementMap, local);
- _locals.update(
+ _state.updateLocal(
_inferrer, _capturedAndBoxed, local, refinedType, node, type);
List<Refinement> refinements = _localRefinementMap[variable];
if (refinements != null) {
@@ -931,12 +902,12 @@
Local local = _localsMap.getLocalVariable(alias);
DartType type = _localsMap.getLocalType(_elementMap, local);
TypeInformation localType =
- _locals.use(_inferrer, _capturedAndBoxed, local);
+ _state.readLocal(_inferrer, _capturedAndBoxed, local);
for (Refinement refinement in refinements) {
localType = _types.refineReceiver(
refinement.selector, refinement.mask, localType,
isConditional: true);
- _locals.update(
+ _state.updateLocal(
_inferrer, _capturedAndBoxed, local, localType, node, type);
}
}
@@ -949,7 +920,7 @@
if (node.iterable is ir.ThisExpression) {
// Any reasonable implementation of an iterator would expose
// this, so we play it safe and assume it will.
- _markThisAsExposed();
+ _state.markThisAsExposed();
}
AbstractValue currentMask;
@@ -990,7 +961,7 @@
Local variable = _localsMap.getLocalVariable(node.variable);
DartType variableType = _localsMap.getLocalType(_elementMap, variable);
- _locals.update(_inferrer, _capturedAndBoxed, variable, currentType,
+ _state.updateLocal(_inferrer, _capturedAndBoxed, variable, currentType,
node.variable, variableType);
JumpTarget target = _localsMap.getJumpTargetForForIn(node);
@@ -1002,10 +973,10 @@
void _setupBreaksAndContinues(JumpTarget target) {
if (target == null) return;
if (target.isContinueTarget) {
- _continuesFor[target] = <LocalsHandler>[];
+ _continuesFor[target] = <LocalState>[];
}
if (target.isBreakTarget) {
- _breaksFor[target] = <LocalsHandler>[];
+ _breaksFor[target] = <LocalState>[];
}
}
@@ -1014,15 +985,15 @@
_breaksFor.remove(element);
}
- List<LocalsHandler> _getBreaks(JumpTarget target) {
- List<LocalsHandler> list = <LocalsHandler>[_locals];
+ List<LocalState> _getBreaks(JumpTarget target) {
+ List<LocalState> list = <LocalState>[_state];
if (target == null) return list;
if (!target.isBreakTarget) return list;
return list..addAll(_breaksFor[target]);
}
- List<LocalsHandler> _getLoopBackEdges(JumpTarget target) {
- List<LocalsHandler> list = <LocalsHandler>[_locals];
+ List<LocalState> _getLoopBackEdges(JumpTarget target) {
+ List<LocalState> list = <LocalState>[_state];
if (target == null) return list;
if (!target.isContinueTarget) return list;
return list..addAll(_continuesFor[target]);
@@ -1031,24 +1002,21 @@
TypeInformation handleLoop(ir.Node node, JumpTarget target, void logic()) {
_loopLevel++;
bool changed = false;
- LocalsHandler localsBefore = _locals;
- FieldInitializationScope fieldScopeBefore = _fieldScope;
- localsBefore.startLoop(_inferrer, node);
+ LocalState stateBefore = _state;
+ stateBefore.startLoop(_inferrer, node);
do {
// Setup (and clear in case of multiple iterations of the loop)
// the lists of breaks and continues seen in the loop.
_setupBreaksAndContinues(target);
- _locals = new LocalsHandler.from(localsBefore, node);
- _fieldScope = new FieldInitializationScope.from(fieldScopeBefore);
+ _state = new LocalState.childPath(stateBefore, node);
logic();
- changed = localsBefore.mergeAll(_inferrer, _getLoopBackEdges(target));
+ changed = stateBefore.mergeAll(_inferrer, _getLoopBackEdges(target));
} while (changed);
_loopLevel--;
- localsBefore.endLoop(_inferrer, node);
+ stateBefore.endLoop(_inferrer, node);
bool keepOwnLocals = node is! ir.DoStatement;
- _locals = localsBefore.mergeAfterBreaks(_inferrer, _getBreaks(target),
+ _state = stateBefore.mergeAfterBreaks(_inferrer, _getBreaks(target),
keepOwnLocals: keepOwnLocals);
- _fieldScope = fieldScopeBefore;
_clearBreaksAndContinues(target);
return null;
}
@@ -1249,7 +1217,7 @@
TypeInformation visitStaticSet(ir.StaticSet node) {
TypeInformation rhsType = visit(node.value);
if (node.value is ir.ThisExpression) {
- _markThisAsExposed();
+ _state.markThisAsExposed();
}
MemberEntity member = _elementMap.getMember(node.target);
AbstractValue mask = _memberData.typeOfSend(node);
@@ -1299,7 +1267,7 @@
TypeInformation rhsType = visit(node.value);
if (node.value is ir.ThisExpression) {
- _markThisAsExposed();
+ _state.markThisAsExposed();
}
if (_inGenerativeConstructor && node.receiver is ir.ThisExpression) {
@@ -1314,7 +1282,7 @@
MemberEntity single = targets.first;
if (single.isField) {
FieldEntity field = single;
- _fieldScope.updateField(field, rhsType);
+ _state.updateField(field, rhsType);
}
}
}
@@ -1375,11 +1343,11 @@
List<IsCheck> positiveTests, List<IsCheck> negativeTests) {
for (IsCheck check in positiveTests) {
if (check.type != null) {
- _locals.narrow(
+ _state.narrowLocal(
_inferrer, _capturedAndBoxed, check.local, check.type, check.node);
} else {
DartType localType = _localsMap.getLocalType(_elementMap, check.local);
- _locals.update(_inferrer, _capturedAndBoxed, check.local,
+ _state.updateLocal(_inferrer, _capturedAndBoxed, check.local,
_types.nullType, check.node, localType);
}
}
@@ -1387,7 +1355,7 @@
if (check.type != null) {
// TODO(johnniwinther): Use negative type knowledge.
} else {
- _locals.narrow(_inferrer, _capturedAndBoxed, check.local,
+ _state.narrowLocal(_inferrer, _capturedAndBoxed, check.local,
_closedWorld.commonElements.objectType, check.node);
}
}
@@ -1399,28 +1367,21 @@
List<IsCheck> negativeTests = <IsCheck>[];
bool simpleCondition =
handleCondition(node.condition, positiveTests, negativeTests);
- LocalsHandler localsBefore = _locals;
- FieldInitializationScope fieldScopeBefore = _fieldScope;
- _locals = new LocalsHandler.from(localsBefore, node);
- _fieldScope = new FieldInitializationScope.from(fieldScopeBefore);
+ LocalState stateBefore = _state;
+ _state = new LocalState.childPath(stateBefore, node);
_updateIsChecks(positiveTests, negativeTests);
visit(node.then);
- LocalsHandler localsAfterThen = _locals;
- FieldInitializationScope fieldScopeAfterThen = _fieldScope;
- _locals = new LocalsHandler.from(localsBefore, node);
- _fieldScope = new FieldInitializationScope.from(fieldScopeBefore);
+ LocalState stateAfterThen = _state;
+ _state = new LocalState.childPath(stateBefore, node);
if (simpleCondition) {
_updateIsChecks(negativeTests, positiveTests);
}
visit(node.otherwise);
- LocalsHandler localsAfterElse = _locals;
- FieldInitializationScope fieldScopeAfterElse = _fieldScope;
+ LocalState stateAfterElse = _state;
- _locals = localsBefore.mergeDiamondFlow(
- _inferrer, localsAfterThen, localsAfterElse);
- _fieldScope = fieldScopeBefore?.mergeDiamondFlow(
- _inferrer, fieldScopeAfterThen, fieldScopeAfterElse);
+ _state =
+ stateBefore.mergeDiamondFlow(_inferrer, stateAfterThen, stateAfterElse);
return null;
}
@@ -1456,15 +1417,13 @@
_negativeIsChecks = <IsCheck>[];
}
visit(node.left, conditionContext: _accumulateIsChecks);
- LocalsHandler localsBefore = _locals;
- FieldInitializationScope fieldScopeBefore = _fieldScope;
- _locals = new LocalsHandler.from(localsBefore, node);
- _fieldScope = new FieldInitializationScope.from(fieldScopeBefore);
+ LocalState stateBefore = _state;
+ _state = new LocalState.childPath(stateBefore, node);
_updateIsChecks(_positiveIsChecks, _negativeIsChecks);
- LocalsHandler narrowed;
+ LocalState narrowed;
if (oldAccumulateIsChecks) {
- narrowed = new LocalsHandler.topLevelCopyOf(_locals);
+ narrowed = new LocalState.deepCopyOf(_state);
} else {
_accumulateIsChecks = false;
_positiveIsChecks = oldPositiveIsChecks;
@@ -1474,17 +1433,16 @@
if (oldAccumulateIsChecks) {
bool invalidatedInRightHandSide(IsCheck check) {
TypeInformation narrowedType =
- narrowed.use(_inferrer, _capturedAndBoxed, check.local);
+ narrowed.readLocal(_inferrer, _capturedAndBoxed, check.local);
TypeInformation currentType =
- _locals.use(_inferrer, _capturedAndBoxed, check.local);
+ _state.readLocal(_inferrer, _capturedAndBoxed, check.local);
return narrowedType != currentType;
}
_positiveIsChecks.removeWhere(invalidatedInRightHandSide);
_negativeIsChecks.removeWhere(invalidatedInRightHandSide);
}
- _locals = localsBefore.mergeFlow(_inferrer, _locals);
- _fieldScope = fieldScopeBefore;
+ _state = stateBefore.mergeFlow(_inferrer, _state);
return _types.boolType;
} else if (node.operator == '||') {
_conditionIsSimple = false;
@@ -1492,16 +1450,13 @@
List<IsCheck> negativeIsChecks = <IsCheck>[];
bool isSimple =
handleCondition(node.left, positiveIsChecks, negativeIsChecks);
- LocalsHandler localsBefore = _locals;
- FieldInitializationScope fieldScopeBefore = _fieldScope;
- _locals = new LocalsHandler.from(_locals, node);
- _fieldScope = new FieldInitializationScope.from(fieldScopeBefore);
+ LocalState stateBefore = _state;
+ _state = new LocalState.childPath(stateBefore, node);
if (isSimple) {
_updateIsChecks(negativeIsChecks, positiveIsChecks);
}
visit(node.right, conditionContext: false);
- _locals = localsBefore.mergeFlow(_inferrer, _locals);
- _fieldScope = fieldScopeBefore;
+ _state = stateBefore.mergeFlow(_inferrer, _state);
return _types.boolType;
}
failedAt(CURRENT_ELEMENT_SPANNABLE,
@@ -1515,24 +1470,17 @@
List<IsCheck> negativeTests = <IsCheck>[];
bool simpleCondition =
handleCondition(node.condition, positiveTests, negativeTests);
- LocalsHandler localsBefore = _locals;
- _locals = new LocalsHandler.from(localsBefore, node);
- FieldInitializationScope fieldScopeBefore = _fieldScope;
- _fieldScope = new FieldInitializationScope.from(fieldScopeBefore);
+ LocalState stateBefore = _state;
+ _state = new LocalState.childPath(stateBefore, node);
_updateIsChecks(positiveTests, negativeTests);
TypeInformation firstType = visit(node.then);
- LocalsHandler localsAfterThen = _locals;
- FieldInitializationScope fieldScopeAfterThen = _fieldScope;
- _locals = new LocalsHandler.from(localsBefore, node);
- _fieldScope = new FieldInitializationScope.from(fieldScopeBefore);
+ LocalState stateAfterThen = _state;
+ _state = new LocalState.childPath(stateBefore, node);
if (simpleCondition) _updateIsChecks(negativeTests, positiveTests);
TypeInformation secondType = visit(node.otherwise);
- LocalsHandler localsAfterElse = _locals;
- FieldInitializationScope fieldScopeAfterElse = _fieldScope;
- _locals = localsBefore.mergeDiamondFlow(
- _inferrer, localsAfterThen, localsAfterElse);
- _fieldScope = fieldScopeBefore?.mergeDiamondFlow(
- _inferrer, fieldScopeAfterThen, fieldScopeAfterElse);
+ LocalState stateAfterElse = _state;
+ _state =
+ stateBefore.mergeDiamondFlow(_inferrer, stateAfterThen, stateAfterElse);
return _types.allocateDiamondPhi(firstType, secondType);
}
@@ -1544,7 +1492,7 @@
// analyzing the closure.
// TODO(herhut): Analyze whether closure exposes this. Possibly using
// whether the created closure as a `thisLocal`.
- _markThisAsExposed();
+ _state.markThisAsExposed();
ClosureRepresentationInfo info = _closureDataLookup.getClosureInfo(node);
@@ -1557,7 +1505,7 @@
_inferrer.recordTypeOfField(field, thisType);
}
TypeInformation localType =
- _locals.use(_inferrer, _capturedAndBoxed, variable);
+ _state.readLocal(_inferrer, _capturedAndBoxed, variable);
// The type is null for type parameters.
if (localType != null) {
_inferrer.recordTypeOfField(field, localType);
@@ -1573,17 +1521,14 @@
if (variable != null) {
Local local = _localsMap.getLocalVariable(variable);
DartType type = _localsMap.getLocalType(_elementMap, local);
- _locals.update(
+ _state.updateLocal(
_inferrer, _capturedAndBoxed, local, localFunctionType, node, type);
}
// We don't put the closure in the work queue of the
// inferrer, because it will share information with its enclosing
// method, like for example the types of local variables.
- LocalsHandler closureLocals =
- new LocalsHandler.from(_locals, node, useOtherTryBlock: false);
- FieldInitializationScope closureFieldScope =
- new FieldInitializationScope.from(_fieldScope);
+ LocalState closureState = new LocalState.closure(_state, node);
KernelTypeGraphBuilder visitor = new KernelTypeGraphBuilder(
_options,
_closedWorld,
@@ -1591,8 +1536,7 @@
info.callMethod,
functionNode,
_localsMap,
- closureLocals,
- closureFieldScope,
+ closureState,
_capturedAndBoxed);
visitor.run();
_inferrer.recordReturnType(info.callMethod, visitor._returnType);
@@ -1655,41 +1599,30 @@
@override
visitTryCatch(ir.TryCatch node) {
- LocalsHandler localsBefore = _locals;
- FieldInitializationScope fieldScopeBefore = _fieldScope;
- _locals = new LocalsHandler.from(localsBefore, node,
- isTry: true, useOtherTryBlock: false);
- _fieldScope = new FieldInitializationScope.from(fieldScopeBefore);
- initializationIsIndefinite();
+ LocalState stateBefore = _state;
+ _state = new LocalState.tryBlock(stateBefore, node);
+ _state.markInitializationAsIndefinite();
visit(node.body);
- LocalsHandler localsAfterBody = _locals;
- _locals = localsBefore.mergeFlow(_inferrer, localsAfterBody);
- _fieldScope = fieldScopeBefore;
+ LocalState stateAfterBody = _state;
+ _state = stateBefore.mergeFlow(_inferrer, stateAfterBody);
for (ir.Catch catchBlock in node.catches) {
- LocalsHandler localsBeforeCatch = _locals;
- FieldInitializationScope fieldScopeBeforeCatch = _fieldScope;
- _locals = new LocalsHandler.from(localsBeforeCatch, catchBlock);
- _fieldScope = new FieldInitializationScope.from(fieldScopeBeforeCatch);
+ LocalState stateBeforeCatch = _state;
+ _state = new LocalState.childPath(stateBeforeCatch, catchBlock);
visit(catchBlock);
- LocalsHandler localsAfterCatch = _locals;
- _locals = localsBeforeCatch.mergeFlow(_inferrer, localsAfterCatch);
- _fieldScope = fieldScopeBeforeCatch;
+ LocalState stateAfterCatch = _state;
+ _state = stateBeforeCatch.mergeFlow(_inferrer, stateAfterCatch);
}
return null;
}
@override
visitTryFinally(ir.TryFinally node) {
- LocalsHandler localsBefore = _locals;
- FieldInitializationScope fieldScopeBefore = _fieldScope;
- _locals = new LocalsHandler.from(localsBefore, node,
- isTry: true, useOtherTryBlock: false);
- _fieldScope = new FieldInitializationScope.from(fieldScopeBefore);
- initializationIsIndefinite();
+ LocalState stateBefore = _state;
+ _state = new LocalState.tryBlock(stateBefore, node);
+ _state.markInitializationAsIndefinite();
visit(node.body);
- LocalsHandler localsAfterBody = _locals;
- _locals = localsBefore.mergeFlow(_inferrer, localsAfterBody);
- _fieldScope = fieldScopeBefore;
+ LocalState stateAfterBody = _state;
+ _state = stateBefore.mergeFlow(_inferrer, stateAfterBody);
visit(node.finalizer);
return null;
}
@@ -1709,15 +1642,15 @@
mask = _types.dynamicType;
}
Local local = _localsMap.getLocalVariable(exception);
- _locals.update(
+ _state.updateLocal(
_inferrer, _capturedAndBoxed, local, mask, node, const DynamicType());
}
ir.VariableDeclaration stackTrace = node.stackTrace;
if (stackTrace != null) {
Local local = _localsMap.getLocalVariable(stackTrace);
// TODO(johnniwinther): Use a mask based on [StackTrace].
- _locals.update(_inferrer, _capturedAndBoxed, local, _types.dynamicType,
- node, const DynamicType());
+ _state.updateLocal(_inferrer, _capturedAndBoxed, local,
+ _types.dynamicType, node, const DynamicType());
}
visit(node.body);
return null;
@@ -1726,13 +1659,13 @@
@override
TypeInformation visitThrow(ir.Throw node) {
visit(node.expression);
- _locals.seenReturnOrThrow = true;
+ _state.seenReturnOrThrow = true;
return _types.nonNullEmpty();
}
@override
TypeInformation visitRethrow(ir.Rethrow node) {
- _locals.seenReturnOrThrow = true;
+ _state.seenReturnOrThrow = true;
return _types.nonNullEmpty();
}
@@ -1749,7 +1682,7 @@
TypeInformation visitSuperPropertyGet(ir.SuperPropertyGet node) {
// TODO(herhut): We could do better here if we knew what we
// are calling does not expose this.
- _markThisAsExposed();
+ _state.markThisAsExposed();
MemberEntity member =
_elementMap.getSuperMember(_analyzedMember, node.name);
@@ -1771,7 +1704,7 @@
TypeInformation visitSuperPropertySet(ir.SuperPropertySet node) {
// TODO(herhut): We could do better here if we knew what we
// are calling does not expose this.
- _markThisAsExposed();
+ _state.markThisAsExposed();
TypeInformation rhsType = visit(node.value);
MemberEntity member =
@@ -1791,7 +1724,7 @@
TypeInformation visitSuperMethodInvocation(ir.SuperMethodInvocation node) {
// TODO(herhut): We could do better here if we knew what we
// are calling does not expose this.
- _markThisAsExposed();
+ _state.markThisAsExposed();
MemberEntity member =
_elementMap.getSuperMember(_analyzedMember, node.name);
@@ -1867,3 +1800,188 @@
Refinement(this.selector, this.mask);
}
+
+class LocalState {
+ final LocalsHandler _locals;
+ final FieldInitializationScope _fields;
+ bool seenReturnOrThrow = false;
+ bool seenBreakOrContinue = false;
+ LocalsHandler _tryBlock;
+
+ LocalState.initial(ir.TreeNode node, {bool inGenerativeConstructor})
+ : this.internal(
+ new LocalsHandler(node),
+ inGenerativeConstructor ? new FieldInitializationScope() : null,
+ null,
+ seenReturnOrThrow: false,
+ seenBreakOrContinue: false);
+
+ LocalState.childPath(LocalState other, ir.TreeNode node)
+ : this.internal(new LocalsHandler.from(other._locals, node, isTry: false),
+ new FieldInitializationScope.from(other._fields), other._tryBlock,
+ seenReturnOrThrow: false, seenBreakOrContinue: false);
+
+ LocalState.closure(LocalState other, ir.TreeNode node)
+ : this.internal(new LocalsHandler.from(other._locals, node, isTry: false),
+ new FieldInitializationScope.from(other._fields), null,
+ seenReturnOrThrow: false, seenBreakOrContinue: false);
+
+ factory LocalState.tryBlock(LocalState other, ir.TreeNode node) {
+ LocalsHandler locals =
+ new LocalsHandler.from(other._locals, node, isTry: true);
+ FieldInitializationScope fieldScope =
+ new FieldInitializationScope.from(other._fields);
+ LocalsHandler tryBlock = locals;
+ return new LocalState.internal(locals, fieldScope, tryBlock,
+ seenReturnOrThrow: false, seenBreakOrContinue: false);
+ }
+
+ LocalState.deepCopyOf(LocalState other)
+ : _locals = new LocalsHandler.deepCopyOf(other._locals),
+ _tryBlock = other._tryBlock,
+ _fields = other._fields;
+
+ LocalState.internal(this._locals, this._fields, this._tryBlock,
+ {this.seenReturnOrThrow, this.seenBreakOrContinue});
+
+ bool get aborts {
+ return seenReturnOrThrow || seenBreakOrContinue;
+ }
+
+ bool get isThisExposed {
+ return _fields == null || _fields.isThisExposed;
+ }
+
+ void markThisAsExposed() {
+ _fields?.isThisExposed = true;
+ }
+
+ void markInitializationAsIndefinite() {
+ _fields?.isIndefinite = true;
+ }
+
+ TypeInformation readField(FieldEntity field) {
+ return _fields.readField(field);
+ }
+
+ void updateField(FieldEntity field, TypeInformation type) {
+ _fields.updateField(field, type);
+ }
+
+ TypeInformation readLocal(InferrerEngine inferrer,
+ Map<Local, FieldEntity> capturedAndBoxed, Local local) {
+ FieldEntity field = capturedAndBoxed[local];
+ if (field != null) {
+ return inferrer.typeOfMember(field);
+ } else {
+ return _locals.use(inferrer, local);
+ }
+ }
+
+ void updateLocal(
+ InferrerEngine inferrer,
+ Map<Local, FieldEntity> capturedAndBoxed,
+ Local local,
+ TypeInformation type,
+ ir.Node node,
+ DartType staticType) {
+ assert(type != null);
+ type = inferrer.types.narrowType(type, staticType);
+
+ FieldEntity field = capturedAndBoxed[local];
+ if (field != null) {
+ inferrer.recordTypeOfField(field, type);
+ } else {
+ _locals.update(inferrer, local, type, node, staticType, _tryBlock);
+ }
+ }
+
+ void narrowLocal(
+ InferrerEngine inferrer,
+ Map<Local, FieldEntity> capturedAndBoxed,
+ Local local,
+ DartType type,
+ ir.Node node) {
+ TypeInformation existing = readLocal(inferrer, capturedAndBoxed, local);
+ TypeInformation newType =
+ inferrer.types.narrowType(existing, type, isNullable: false);
+ updateLocal(inferrer, capturedAndBoxed, local, newType, node, type);
+ }
+
+ LocalState mergeFlow(InferrerEngine inferrer, LocalState other) {
+ seenReturnOrThrow = false;
+ seenBreakOrContinue = false;
+
+ if (other.aborts) {
+ return this;
+ }
+ LocalsHandler locals = _locals.mergeFlow(inferrer, other._locals);
+ return new LocalState.internal(locals, _fields, _tryBlock,
+ seenReturnOrThrow: seenReturnOrThrow,
+ seenBreakOrContinue: seenBreakOrContinue);
+ }
+
+ LocalState mergeDiamondFlow(
+ InferrerEngine inferrer, LocalState thenBranch, LocalState elseBranch) {
+ seenReturnOrThrow =
+ thenBranch.seenReturnOrThrow && elseBranch.seenReturnOrThrow;
+ seenBreakOrContinue =
+ thenBranch.seenBreakOrContinue && elseBranch.seenBreakOrContinue;
+
+ LocalsHandler locals;
+ if (aborts) {
+ locals = _locals;
+ } else if (thenBranch.aborts) {
+ locals = _locals.mergeFlow(inferrer, elseBranch._locals, inPlace: true);
+ } else if (elseBranch.aborts) {
+ locals = _locals.mergeFlow(inferrer, thenBranch._locals, inPlace: true);
+ } else {
+ locals = _locals.mergeDiamondFlow(
+ inferrer, thenBranch._locals, elseBranch._locals);
+ }
+
+ FieldInitializationScope fieldScope = _fields?.mergeDiamondFlow(
+ inferrer, thenBranch._fields, elseBranch._fields);
+ return new LocalState.internal(locals, fieldScope, _tryBlock,
+ seenReturnOrThrow: seenReturnOrThrow,
+ seenBreakOrContinue: seenBreakOrContinue);
+ }
+
+ LocalState mergeAfterBreaks(InferrerEngine inferrer, List<LocalState> states,
+ {bool keepOwnLocals: true}) {
+ bool allBranchesAbort = true;
+ for (LocalState state in states) {
+ allBranchesAbort = allBranchesAbort && state.seenReturnOrThrow;
+ }
+
+ keepOwnLocals = keepOwnLocals && !seenReturnOrThrow;
+
+ LocalsHandler locals = _locals.mergeAfterBreaks(
+ inferrer,
+ states
+ .where((LocalState state) => !state.seenReturnOrThrow)
+ .map((LocalState state) => state._locals),
+ keepOwnLocals: keepOwnLocals);
+ seenReturnOrThrow = allBranchesAbort && !keepOwnLocals;
+ return new LocalState.internal(locals, _fields, _tryBlock,
+ seenReturnOrThrow: seenReturnOrThrow,
+ seenBreakOrContinue: seenBreakOrContinue);
+ }
+
+ bool mergeAll(InferrerEngine inferrer, List<LocalState> states) {
+ assert(!seenReturnOrThrow);
+ return _locals.mergeAll(
+ inferrer,
+ states
+ .where((LocalState state) => !state.seenReturnOrThrow)
+ .map((LocalState state) => state._locals));
+ }
+
+ void startLoop(InferrerEngine inferrer, ir.Node loop) {
+ _locals.startLoop(inferrer, loop);
+ }
+
+ void endLoop(InferrerEngine inferrer, ir.Node loop) {
+ _locals.endLoop(inferrer, loop);
+ }
+}
diff --git a/pkg/compiler/lib/src/inferrer/locals_handler.dart b/pkg/compiler/lib/src/inferrer/locals_handler.dart
index 2ebc446..16fc757 100644
--- a/pkg/compiler/lib/src/inferrer/locals_handler.dart
+++ b/pkg/compiler/lib/src/inferrer/locals_handler.dart
@@ -251,69 +251,37 @@
*/
class LocalsHandler {
final VariableScope _locals;
- LocalsHandler _tryBlock;
- bool seenReturnOrThrow = false;
- bool seenBreakOrContinue = false;
-
- bool get aborts {
- return seenReturnOrThrow || seenBreakOrContinue;
- }
-
- bool get inTryBlock => _tryBlock != null;
-
- LocalsHandler.internal(ir.Node block, this._locals, this._tryBlock);
LocalsHandler(ir.Node block)
- : _locals = new VariableScope(block, isTry: false),
- _tryBlock = null;
+ : _locals = new VariableScope(block, isTry: false);
LocalsHandler.from(LocalsHandler other, ir.Node block,
{bool isTry: false, bool useOtherTryBlock: true})
- : _locals =
- new VariableScope(block, isTry: isTry, parent: other._locals) {
- _tryBlock = useOtherTryBlock ? other._tryBlock : this;
- }
+ : _locals = new VariableScope(block, isTry: isTry, parent: other._locals);
LocalsHandler.deepCopyOf(LocalsHandler other)
- : _locals = new VariableScope.deepCopyOf(other._locals),
- _tryBlock = other._tryBlock;
+ : _locals = new VariableScope.deepCopyOf(other._locals);
- LocalsHandler.topLevelCopyOf(LocalsHandler other)
- : _locals = new VariableScope.topLevelCopyOf(other._locals),
- _tryBlock = other._tryBlock;
-
- TypeInformation use(InferrerEngine inferrer,
- Map<Local, FieldEntity> capturedAndBoxed, Local local) {
- FieldEntity field = capturedAndBoxed[local];
- if (field != null) {
- return inferrer.typeOfMember(field);
- } else {
- return _locals[local];
- }
+ TypeInformation use(InferrerEngine inferrer, Local local) {
+ return _locals[local];
}
- void update(InferrerEngine inferrer, Map<Local, FieldEntity> capturedAndBoxed,
- Local local, TypeInformation type, ir.Node node, DartType staticType) {
- assert(type != null);
- type = inferrer.types.narrowType(type, staticType);
-
- FieldEntity field = capturedAndBoxed[local];
- if (field != null) {
- inferrer.recordTypeOfField(field, type);
- } else if (inTryBlock) {
+ void update(InferrerEngine inferrer, Local local, TypeInformation type,
+ ir.Node node, DartType staticType, LocalsHandler tryBlock) {
+ if (tryBlock != null) {
// We don't know if an assignment in a try block
// will be executed, so all assignments in that block are
// potential types after we have left it. We update the parent
// of the try block so that, at exit of the try block, we get
// the right phi for it.
- TypeInformation existing = _tryBlock._locals.parent[local];
+ TypeInformation existing = tryBlock._locals.parent[local];
if (existing != null) {
TypeInformation phiType = inferrer.types.allocatePhi(
- _tryBlock._locals.block, local, existing,
- isTry: _tryBlock._locals.isTry);
+ tryBlock._locals.block, local, existing,
+ isTry: tryBlock._locals.isTry);
TypeInformation inputType =
inferrer.types.addPhiInput(local, phiType, type);
- _tryBlock._locals.parent[local] = inputType;
+ tryBlock._locals.parent[local] = inputType;
}
// Update the current handler unconditionally with the new
// type.
@@ -323,30 +291,21 @@
}
}
- void narrow(InferrerEngine inferrer, Map<Local, FieldEntity> capturedAndBoxed,
- Local local, DartType type, ir.Node node) {
- TypeInformation existing = use(inferrer, capturedAndBoxed, local);
- TypeInformation newType =
- inferrer.types.narrowType(existing, type, isNullable: false);
- update(inferrer, capturedAndBoxed, local, newType, node, type);
- }
-
/// Returns the join between this locals handler and [other] which models the
/// flow through either this or [other].
- LocalsHandler mergeFlow(InferrerEngine inferrer, LocalsHandler other) {
- seenReturnOrThrow = false;
- seenBreakOrContinue = false;
-
- if (other.aborts) {
- return this;
- } else {
- other._locals.forEachOwnLocal((Local local, TypeInformation type) {
- TypeInformation myType = _locals[local];
- if (myType == null) return; // Variable is only defined in [other].
- if (type == myType) return;
- _locals[local] = inferrer.types.allocateDiamondPhi(myType, type);
- });
- }
+ ///
+ /// If [inPlace] is `true`, the variable types in this locals handler are
+ /// replaced by the variables types in [other]. Otherwise the variable types
+ /// from both are merged with a phi type.
+ LocalsHandler mergeFlow(InferrerEngine inferrer, LocalsHandler other,
+ {bool inPlace: false}) {
+ other._locals.forEachOwnLocal((Local local, TypeInformation type) {
+ TypeInformation myType = _locals[local];
+ if (myType == null) return; // Variable is only defined in [other].
+ if (type == myType) return;
+ _locals[local] =
+ inPlace ? type : inferrer.types.allocateDiamondPhi(myType, type);
+ });
return this;
}
@@ -355,48 +314,27 @@
LocalsHandler mergeDiamondFlow(InferrerEngine inferrer,
LocalsHandler thenBranch, LocalsHandler elseBranch) {
assert(elseBranch != null);
- seenReturnOrThrow =
- thenBranch.seenReturnOrThrow && elseBranch.seenReturnOrThrow;
- seenBreakOrContinue =
- thenBranch.seenBreakOrContinue && elseBranch.seenBreakOrContinue;
- if (aborts) return this;
- void inPlaceUpdateOneBranch(LocalsHandler other) {
- other._locals.forEachOwnLocal((Local local, TypeInformation type) {
- TypeInformation myType = _locals[local];
- if (myType == null) return; // Variable is only defined in [other].
- if (type == myType) return;
- _locals[local] = type;
- });
- }
-
- if (thenBranch.aborts) {
- inPlaceUpdateOneBranch(elseBranch);
- } else if (elseBranch.aborts) {
- inPlaceUpdateOneBranch(thenBranch);
- } else {
- void mergeLocal(Local local) {
- TypeInformation myType = _locals[local];
- if (myType == null) return;
- TypeInformation elseType = elseBranch._locals[local];
- TypeInformation thenType = thenBranch._locals[local];
- if (thenType == elseType) {
- _locals[local] = thenType;
- } else {
- _locals[local] =
- inferrer.types.allocateDiamondPhi(thenType, elseType);
- }
+ void mergeLocal(Local local) {
+ TypeInformation myType = _locals[local];
+ if (myType == null) return;
+ TypeInformation elseType = elseBranch._locals[local];
+ TypeInformation thenType = thenBranch._locals[local];
+ if (thenType == elseType) {
+ _locals[local] = thenType;
+ } else {
+ _locals[local] = inferrer.types.allocateDiamondPhi(thenType, elseType);
}
-
- thenBranch._locals.forEachOwnLocal((Local local, _) {
- mergeLocal(local);
- });
- elseBranch._locals.forEachOwnLocal((Local local, _) {
- // Discard locals we already processed when iterating over
- // [thenBranch]'s locals.
- if (!thenBranch._locals.updates(local)) mergeLocal(local);
- });
}
+
+ thenBranch._locals.forEachOwnLocal((Local local, _) {
+ mergeLocal(local);
+ });
+ elseBranch._locals.forEachOwnLocal((Local local, _) {
+ // Discard locals we already processed when iterating over
+ // [thenBranch]'s locals.
+ if (!thenBranch._locals.updates(local)) mergeLocal(local);
+ });
return this;
}
@@ -431,7 +369,7 @@
* labeled statement that do not break out.
*/
LocalsHandler mergeAfterBreaks(
- InferrerEngine inferrer, List<LocalsHandler> handlers,
+ InferrerEngine inferrer, Iterable<LocalsHandler> handlers,
{bool keepOwnLocals: true}) {
ir.Node level = _locals.block;
// Use a separate locals handler to perform the merge in, so that Phi
@@ -440,15 +378,13 @@
LocalsHandler merged =
new LocalsHandler.from(this, level, isTry: _locals.isTry);
Set<Local> seenLocals = new Setlet<Local>();
- bool allBranchesAbort = true;
// Merge all other handlers.
for (LocalsHandler handler in handlers) {
- allBranchesAbort = allBranchesAbort && handler.seenReturnOrThrow;
merged._mergeHandler(inferrer, handler, seenLocals);
}
// If we want to keep own locals, we merge [seenLocals] from [this] into
// [merged] to update the Phi nodes with original values.
- if (keepOwnLocals && !seenReturnOrThrow) {
+ if (keepOwnLocals) {
for (Local variable in seenLocals) {
TypeInformation originalType = _locals[variable];
if (originalType != null) {
@@ -462,8 +398,6 @@
merged._locals.forEachOwnLocal((Local variable, TypeInformation type) {
_locals[variable] = inferrer.types.simplifyPhi(level, variable, type);
});
- seenReturnOrThrow =
- allBranchesAbort && (!keepOwnLocals || seenReturnOrThrow);
return this;
}
@@ -475,7 +409,6 @@
*/
bool _mergeHandler(InferrerEngine inferrer, LocalsHandler other,
[Set<Local> seen]) {
- if (other.seenReturnOrThrow) return false;
bool changed = false;
other._locals.forEachLocalUntilNode(_locals.block, (local, otherType) {
TypeInformation myType = _locals[local];
@@ -500,9 +433,8 @@
* Merge all [LocalsHandler] in [handlers] into this handler.
* Returns whether a local in this handler has changed.
*/
- bool mergeAll(InferrerEngine inferrer, List<LocalsHandler> handlers) {
+ bool mergeAll(InferrerEngine inferrer, Iterable<LocalsHandler> handlers) {
bool changed = false;
- assert(!seenReturnOrThrow);
handlers.forEach((other) {
changed = _mergeHandler(inferrer, other) || changed;
});