// Return false if the inference is illegal. Currently this only happens if the var is reassigned
  // to incompatible
  // type inside the loop.
  public boolean add(VariableExpression ve, ClassNode type) {
    if (defVars == null) defVars = FHashMap.emptyMap;

    if (ve.getAccessedVariable() != null) {
      defVars = defVars.put(ve.getAccessedVariable(), type);
      //            dumpMap(ve);
    } else {
      boolean done = false;
      for (Map.Entry<Variable, ClassNode> variable : defVars.entrySet()) {
        if (variable.getKey().getName().equals(ve.getName())) {
          defVars = defVars.put(variable.getKey(), type);
          //                    dumpMap(ve);
          done = true;
          break;
        }
      }

      if (!done) {
        defVars = defVars.put(ve, type);
        //                dumpMap(ve);
      }
    }

    if (parentScopeInference != null && parentScopeInference.defVars != null) {
      final ClassNode oldType = parentScopeInference.defVars.get(ve.getAccessedVariable());
      if (oldType != null) {
        if (!TypeUtil.isDirectlyAssignableFrom(oldType, type)) {
          return false;
        }
      }
    }

    return true;
  }
 // TODO handle local variables
 private void checkForFinal(final Expression expression, VariableExpression ve) {
   Variable v = ve.getAccessedVariable();
   boolean isFinal = isFinal(v.getModifiers());
   boolean isParameter = v instanceof Parameter;
   if (isFinal && isParameter) {
     addError("Cannot assign a value to final variable '" + v.getName() + "'", expression);
   }
 }
 @Override
 public void visitVariableExpression(final VariableExpression expression) {
   super.visitVariableExpression(expression);
   if (inAssignment) {
     Map<Variable, VariableState> state = getState();
     Variable key = expression.getAccessedVariable();
     VariableState variableState = state.get(key);
     if (variableState == VariableState.is_uninitialized) {
       variableState = VariableState.is_var;
       state.put(key, variableState);
     }
   }
 }
 protected Expression transformVariableExpression(VariableExpression ve) {
   Variable v = ve.getAccessedVariable();
   if (v != null && v instanceof DynamicVariable) {
     Expression result = findStaticFieldOrPropAccessorImportFromModule(v.getName());
     if (result != null) {
       setSourcePosition(result, ve);
       if (inAnnotation) {
         result = transformInlineConstants(result);
       }
       return result;
     }
   }
   return ve;
 }
 @Override
 public void visitBlockStatement(final BlockStatement block) {
   Set<VariableExpression> old = declaredFinalVariables;
   declaredFinalVariables = new HashSet<VariableExpression>();
   super.visitBlockStatement(block);
   if (callback != null) {
     Map<Variable, VariableState> state = getState();
     for (VariableExpression declaredFinalVariable : declaredFinalVariables) {
       VariableState variableState = state.get(declaredFinalVariable.getAccessedVariable());
       if (variableState == null || variableState != VariableState.is_final) {
         callback.variableNotAlwaysInitialized(declaredFinalVariable);
       }
     }
   }
   declaredFinalVariables = old;
 }
  public ClassNode get(VariableExpression ve) {
    if (defVars == null) return ClassHelper.OBJECT_TYPE;
    else {
      final Variable accessed = ve.getAccessedVariable();
      if (accessed != null) return defVars.get(accessed);
      else {
        for (Map.Entry<Variable, ClassNode> variable : defVars.entrySet()) {
          if (variable.getKey().getName().equals(ve.getName())) {
            return variable.getValue();
          }
        }

        return null;
      }
    }
  }
  private boolean doAssignmentToLocalVariable(String method, BinaryExpression binExp) {
    Expression left = binExp.getLeftExpression();
    if (left instanceof VariableExpression) {
      VariableExpression ve = (VariableExpression) left;
      Variable v = ve.getAccessedVariable();
      if (v instanceof DynamicVariable) return false;
      if (v instanceof PropertyExpression) return false;
      /* field and declaration we don't return false */
    } else {
      return false;
    }

    evaluateBinaryExpression(method, binExp);
    getController().getOperandStack().dup();
    getController().getCompileStack().pushLHS(true);
    binExp.getLeftExpression().visit(getController().getAcg());
    getController().getCompileStack().popLHS();

    return true;
  }
  private void checkFinalFieldAccess(Expression expression) {
    if (!(expression instanceof VariableExpression) && !(expression instanceof PropertyExpression))
      return;
    Variable v = null;
    if (expression instanceof VariableExpression) {
      VariableExpression ve = (VariableExpression) expression;
      v = ve.getAccessedVariable();
    } else {
      PropertyExpression propExp = ((PropertyExpression) expression);
      Expression objectExpression = propExp.getObjectExpression();
      if (objectExpression instanceof VariableExpression) {
        VariableExpression varExp = (VariableExpression) objectExpression;
        if (varExp.isThisExpression()) {
          v = currentClass.getDeclaredField(propExp.getPropertyAsString());
        }
      }
    }
    if (v instanceof FieldNode) {
      FieldNode fn = (FieldNode) v;

      /*
       *  if it is static final but not accessed inside a static constructor, or,
       *  if it is an instance final but not accessed inside a instance constructor, it is an error
       */
      boolean isFinal = fn.isFinal();
      boolean isStatic = fn.isStatic();
      boolean error =
          isFinal && ((isStatic && !inStaticConstructor) || (!isStatic && !inConstructor));

      if (error)
        addError(
            "cannot modify"
                + (isStatic ? " static" : "")
                + " final field '"
                + fn.getName()
                + "' outside of "
                + (isStatic ? "static initialization block." : "constructor."),
            expression);
    }
  }