anchor.diff:      }
       // This is matched by the call to [forEach_end] in
       // [inferElement], [inferMapEntry] or [inferForInStatement].
  -    inferrer.flowAnalysis.forEach_bodyBegin(node, variable, variable.type);
  -    if (syntheticVariableSet != null) {
  -      inferrer.flowAnalysis.write(syntheticVariableSet.variable, variable.type);
  -    }
  -    if (syntheticAssignment != null && !skipStatement) {
  -      ExpressionInferenceResult result = inferrer.inferExpression(
  -          syntheticAssignment, const UnknownType(), !inferrer.isTopLevel,
  -          isVoidAllowed: true);
  -      syntheticAssignment = result.expression;
  -    }
  +    inferrer.flowAnalysis.forEach_bodyBegin(node, variable, inferredType);
  +    syntheticAssignment = forInVariable.inferAssignment(inferrer, inferredType);
       if (expressionEffects != null) {
         StatementInferenceResult result =
             inferrer.inferStatement(expressionEffects);
         expressionEffects =
             result.hasChanged ? result.statement : expressionEffects;
  -    }
  -
  -    if (syntheticWriteType != null) {
  -      rhs = inferrer.ensureAssignable(
  -          greatestClosure(inferrer.coreTypes, syntheticWriteType),
  -          variable.type,
  -          rhs,
  -          errorTemplate: templateForInLoopElementTypeNotAssignable,
  -          isVoidAllowed: true);
  -      if (syntheticVariableSet != null) {
  -        syntheticVariableSet.value = rhs..parent = syntheticVariableSet;
  -      } else if (syntheticPropertySet != null) {
  -        syntheticPropertySet.value = rhs..parent = syntheticPropertySet;
  -      } else if (syntheticSuperPropertySet != null) {
  -        syntheticSuperPropertySet.value = rhs
  -          ..parent = syntheticSuperPropertySet;
  -      } else if (syntheticStaticSet != null) {
  -        syntheticStaticSet.value = rhs..parent = syntheticStaticSet;
  -      }
       }
       return new ForInResult(variable, iterableResult.expression,
           syntheticAssignment, expressionEffects);
  
positive.code:       {bool isAsync: false,
        bool hasProblem}) {
      assert(hasProblem != null);
      DartType elementType;
      bool typeChecksNeeded = !inferrer.isTopLevel;
      DartType syntheticWriteType;
      Expression rhs;
      // If `true`, the synthetic statement should not be visited.
      bool skipStatement = false;
      // TODO(johnniwinther): Refactor handling of synthetic assignment to avoid
      // case handling here.
      VariableSet syntheticVariableSet;
      PropertySet syntheticPropertySet;
      SuperPropertySet syntheticSuperPropertySet;
      StaticSet syntheticStaticSet;
      if (syntheticAssignment is VariableSet) {
        syntheticVariableSet = syntheticAssignment;
        syntheticWriteType = elementType = syntheticVariableSet.variable.type;
        rhs = syntheticVariableSet.value;
        // This expression is fully handled in this method so we should not
        // visit the synthetic statement.
        skipStatement = true;
      } else if (syntheticAssignment is PropertySet) {
        syntheticPropertySet = syntheticAssignment;
        ExpressionInferenceResult receiverResult = inferrer.inferExpression(
            syntheticPropertySet.receiver, const UnknownType(), true);
        syntheticPropertySet.receiver = receiverResult.expression
          ..parent = syntheticPropertySet;
        DartType receiverType = receiverResult.inferredType;
        ObjectAccessTarget writeTarget = inferrer.findInterfaceMember(
            receiverType,
            syntheticPropertySet.name,
            syntheticPropertySet.fileOffset,
            setter: true,
            instrumented: true,
            includeExtensionMethods: true);
        syntheticWriteType =
            elementType = inferrer.getSetterType(writeTarget, receiverType);
        Expression error = inferrer.reportMissingInterfaceMember(
            writeTarget,
            receiverType,
            syntheticPropertySet.name,
            syntheticPropertySet.fileOffset,
            templateUndefinedSetter);
        if (error != null) {
          rhs = error;
        } else {
          if (writeTarget.isInstanceMember) {
            if (inferrer.instrumentation != null &&
                receiverType == const DynamicType()) {
              inferrer.instrumentation.record(
                  inferrer.uriForInstrumentation,
                  syntheticPropertySet.fileOffset,
                  'target',
                  new InstrumentationValueForMember(writeTarget.member));
            }
            syntheticPropertySet.interfaceTarget = writeTarget.member;
          }
          rhs = syntheticPropertySet.value;
        }
      } else if (syntheticAssignment is SuperPropertySet) {
        syntheticSuperPropertySet = syntheticAssignment;
        DartType receiverType = inferrer.thisType;
        ObjectAccessTarget writeTarget = inferrer.findInterfaceMember(
            receiverType,
            syntheticSuperPropertySet.name,
            syntheticSuperPropertySet.fileOffset,
            setter: true,
            instrumented: true);
        if (writeTarget.isInstanceMember) {
          syntheticSuperPropertySet.interfaceTarget = writeTarget.member;
        }
        syntheticWriteType =
            elementType = inferrer.getSetterType(writeTarget, receiverType);
        rhs = syntheticSuperPropertySet.value;
      } else if (syntheticAssignment is StaticSet) {
        syntheticStaticSet = syntheticAssignment;
        syntheticWriteType = elementType = syntheticStaticSet.target.setterType;
        rhs = syntheticStaticSet.value;
      } else if (syntheticAssignment is InvalidExpression || hasProblem) {
        elementType = const UnknownType();
      } else {
        unhandled(
            "${syntheticAssignment.runtimeType}",
            "handleForInStatementWithoutVariable",
            syntheticAssignment.fileOffset,
            inferrer.helper.uri);
      }
  
      ExpressionInferenceResult iterableResult = inferForInIterable(
          iterable, elementType, typeChecksNeeded,
          isAsync: isAsync);
  
negative.code:     return new ExpressionInferenceResult(inferredType, iterable);
    }
  
    ForInVariable computeForInVariable(
        Expression syntheticAssignment, bool hasProblem) {
      if (syntheticAssignment is VariableSet) {
        return new LocalForInVariable(syntheticAssignment);
      } else if (syntheticAssignment is PropertySet) {
        return new PropertyForInVariable(syntheticAssignment);
      } else if (syntheticAssignment is SuperPropertySet) {
        return new SuperPropertyForInVariable(syntheticAssignment);
      } else if (syntheticAssignment is StaticSet) {
        return new StaticForInVariable(syntheticAssignment);
      } else if (syntheticAssignment is InvalidExpression || hasProblem) {
        return new InvalidForInVariable(syntheticAssignment);
      } else {
        return unhandled(
            "${syntheticAssignment.runtimeType}",
            "handleForInStatementWithoutVariable",
            syntheticAssignment.fileOffset,
            inferrer.helper.uri);
      }
    }
  
    ForInResult handleForInWithoutVariable(
        TreeNode node,
        VariableDeclaration variable,
  