TypePtr VariableTable::setType(AnalysisResultConstPtr ar, Symbol *sym,
                               TypePtr type, bool coerce) {
  bool force_coerce = coerce;
  int mask = GetVarClassMaskForSym(sym);
  if (m_forcedVariants & mask && !sym->isHidden()) {
    type = Type::Variant;
    force_coerce = true;
  }
  TypePtr ret = SymbolTable::setType(ar, sym, type, force_coerce);
  if (!ret) return ret;

  if (sym->isGlobal() && !isGlobalTable(ar)) {
    ar->lock()->getVariables()->setType(ar, sym->getName(), type, coerce);
  }

  if (coerce) {
    if (sym->isParameter()) {
      FunctionScope *func = dynamic_cast<FunctionScope *>(&m_blockScope);
      assert(func);
      TypePtr paramType = func->setParamType(ar,
                                             sym->getParameterIndex(), type);
      if (!Type::SameType(paramType, type)) {
        return setType(ar, sym, paramType, true); // recursively
      }
    }
  }
  return ret;
}
TypePtr VariableTable::add(Symbol *sym, TypePtr type,
                           bool implicit, AnalysisResultConstPtr ar,
                           ConstructPtr construct,
                           ModifierExpressionPtr modifiers) {
  if (getAttribute(InsideStaticStatement)) {
    addStaticVariable(sym, ar);
    if (ClassScope::NeedStaticArray(getClassScope(), getFunctionScope())) {
      forceVariant(ar, sym->getName(), AnyVars);
    }
  } else if (getAttribute(InsideGlobalStatement)) {
    sym->setGlobal();
    m_hasGlobal = true;
    AnalysisResult::Locker lock(ar);
    if (!isGlobalTable(ar)) {
      lock->getVariables()->add(sym->getName(), type, implicit,
                                ar, construct, modifiers);
    }
    assert(type->is(Type::KindOfSome) || type->is(Type::KindOfAny));
    TypePtr varType = ar->getVariables()->getFinalType(sym->getName());
    if (varType) {
      type = varType;
    } else {
      lock->getVariables()->setType(ar, sym->getName(), type, true);
    }
  } else if (!sym->isHidden() && isPseudoMainTable()) {
    // A variable used in a pseudomain
    // only need to do this once... should mark the sym.
    ar->lock()->getVariables()->add(sym->getName(), type, implicit, ar,
                                    construct, modifiers);
  }

  if (modifiers) {
    if (modifiers->isProtected()) {
      sym->setProtected();
    } else if (modifiers->isPrivate()) {
      sym->setPrivate();
      m_hasPrivate = true;
      if (!sym->isStatic() && !modifiers->isStatic()) {
        m_hasNonStaticPrivate = true;
      }
    }
    if (modifiers->isStatic()) {
      addStaticVariable(sym, ar);
    }
  }

  type = setType(ar, sym, type, true);
  sym->setDeclaration(construct);

  if (!implicit && m_blockScope.isFirstPass()) {
    if (!sym->getValue()) {
      sym->setValue(construct);
    }
  }
  return type;
}
void VariableTable::addStaticVariable(Symbol *sym,
                                      AnalysisResultConstPtr ar,
                                      bool member /* = false */) {
  if (isGlobalTable(ar) ||
      sym->isStatic()) {
    return; // a static variable at global scope is the same as non-static
  }

  addStaticVariable(sym, ar->lock().get(), member);
}
TypePtr VariableTable::checkVariable(Symbol *sym, TypePtr type,
                                     bool coerce, AnalysisResultConstPtr ar,
                                     ConstructPtr construct) {

  // Variable used in pseudomain
  if (!sym->isHidden() && isPseudoMainTable()) {
    // only need to do this once... should mark the sym.
    ar->lock()->getVariables()->checkVariable(sym->getName(), type,
                                              coerce, ar, construct);
  }

  if (!sym->declarationSet()) {
    type = setType(ar, sym, type, coerce);
    sym->setDeclaration(construct);
    return type;
  }

  return setType(ar, sym, type, coerce);
}