Logo Search packages:      
Sourcecode: fauhdlc version File versions

ResolveTypes.cpp

/* $Id: ResolveTypes.cpp 4323 2009-01-27 13:48:12Z potyra $
 * ResolveTypes: perform type analysis.
 *
 * Copyright (C) 2007-2009 FAUmachine Team <info@faumachine.org>.
 * This program is free software. You can redistribute it and/or modify it
 * under the terms of the GNU General Public License, either version 2 of
 * the License, or (at your option) any later version. See COPYING.
 */

#include <cassert>
#include <algorithm>
#include "frontend/visitor/ResolveTypes.hpp"

#include "frontend/ast/ConstInteger.hpp"
#include "frontend/ast/ConstReal.hpp"
#include "frontend/ast/Entity.hpp"
#include "frontend/ast/SymbolDeclaration.hpp"
#include "frontend/ast/ValDeclaration.hpp"
#include "frontend/ast/SignalDeclaration.hpp"
#include "frontend/ast/ConstantDeclaration.hpp"
#include "frontend/ast/Expression.hpp"
#include "frontend/ast/IfStat.hpp"
#include "frontend/ast/NullStat.hpp"
#include "frontend/ast/ForLoopStat.hpp"
#include "frontend/ast/WhileLoopStat.hpp"
#include "frontend/ast/NextStat.hpp"
#include "frontend/ast/VarAssignStat.hpp"
#include "frontend/ast/WaitStat.hpp"
#include "frontend/ast/ExitStat.hpp"
#include "frontend/ast/SigAssignStat.hpp"
#include "frontend/ast/WaveFormElem.hpp"
#include "frontend/ast/ReturnStat.hpp"
#include "frontend/ast/ProcCallStat.hpp"
#include "frontend/ast/AssertStat.hpp"
#include "frontend/ast/VarDeclaration.hpp"
#include "frontend/ast/DiscreteRange.hpp"
#include "frontend/ast/CaseStat.hpp"
#include "frontend/ast/CaseAlternative.hpp"
#include "frontend/ast/Others.hpp"
#include "frontend/ast/Architecture.hpp"
#include "frontend/ast/AssociationElement.hpp"
#include "frontend/ast/FunctionDeclaration.hpp"
#include "frontend/ast/ProcedureDeclaration.hpp"
#include "frontend/ast/CompInstStat.hpp"
#include "frontend/ast/Package.hpp"
#include "frontend/ast/PackageBody.hpp"
#include "frontend/ast/Process.hpp"
#include "frontend/ast/SubprogBody.hpp"
#include "frontend/ast/CondalSigAssign.hpp"
#include "frontend/ast/EnumerationType.hpp"
#include "frontend/ast/PhysicalType.hpp"
#include "frontend/ast/PhysicalTypeUnit.hpp"
#include "frontend/ast/RangeConstraintType.hpp"
#include "frontend/ast/UnconstrainedArrayType.hpp"
#include "frontend/ast/RecordType.hpp"
#include "frontend/ast/Aggregate.hpp"
#include "frontend/ast/EnumerationElement.hpp"
#include "frontend/ast/Subscript.hpp"
#include "frontend/ast/TypeConversion.hpp"
#include "frontend/reporting/ErrorRegistry.hpp"
#include "frontend/reporting/CompileError.hpp"
#include "util/MiscUtil.hpp"
#include "frontend/ast/SimpleName.hpp"
#include "frontend/ast/SelectedName.hpp"
#include "frontend/ast/AttributeName.hpp"
#include "frontend/ast/FunctionCall.hpp"
#include "frontend/ast/Slice.hpp"
#include "frontend/ast/TemporaryName.hpp"
#include "frontend/ast/ReturnStat.hpp"
#include "frontend/ast/AttributeSpecification.hpp"
#include "frontend/visitor/LookupTypes.hpp"

#define SLICE_DEBUG 0
#define SELECTION_DEBUG 0
#define FUNCCALLS_DEBUG 0

namespace ast {

void
00080 ResolveTypes::visit(CompInstStat &node)
{
      if (node.genericMap != NULL) {
            for (std::list<AssociationElement*>::const_iterator i = 
                  node.genericMap->begin(); i != node.genericMap->end();
                  i++) {
      
                  //FIXME this may fail for positional association.
                  //      (because there, the formal is missing, but
                  //      the wanted type is the projected argument's
                  //      type)
                  this->typeCandidates.clear();
                  (*i)->accept(*this);
                  if (! this->needUniqueType(**i)) {
                        return;
                  }
                  // pin down type
                  (*i)->accept(*this);
                  assert(this->typeCandidates.size() == 1);
            }
      }

      if (node.portMap != NULL) {
            for (std::list<AssociationElement*>::const_iterator i = 
                  node.portMap->begin(); i != node.portMap->end();
                  i++) {
      
                  //FIXME same as above.
                  this->typeCandidates.clear();
                  (*i)->accept(*this);

                  bool ret = this->needUniqueType(**i);
                  if (! ret) {
                        // error already reported, skip.
                        continue;
                  }

                  // pin down type
                  (*i)->accept(*this);
                  assert(this->typeCandidates.size() == 1);
            }
      }
      this->typeCandidates.clear();
}

void
00126 ResolveTypes::visit(AssociationElement &node)
{
      bool mustSingle = (this->typeCandidates.size() == 1);

      if (node.formal != NULL) {
            node.formal->accept(*this);
      }
      
      if (node.actual != NULL) {
            node.actual->accept(*this);
      }

      if (mustSingle) {
            this->needUniqueType(node);
      }
}

void
00144 ResolveTypes::visit(UnconstrainedArrayType &node)
{
      assert(node.indexTypes != NULL);
      node.baseType = BASE_TYPE_ARRAY;
      assert(node.containerType != NULL);
      node.containerType->accept(*this);
}

void
00153 ResolveTypes::visit(DiscreteRange &node)
{
      if (node.rangeName != NULL) {
            this->processDRByName(node);
            return;
      }

      assert(node.from != NULL);
      assert(node.to != NULL);

      // gather types of from.
      typeSetT backup = this->typeCandidates;
      node.from->accept(*this);
      typeSetT fromT = this->typeCandidates;
      this->typeCandidates = backup;
      node.to->accept(*this);

      //propagate a RangeConstraintType based on the left bound 
      //(usually the index type) with an additional constraint
      if ((fromT.size() == 1) && (this->typeCandidates.size() == 1)) {
            const TypeDeclaration *left = *fromT.begin();
            const TypeDeclaration *right = *this->typeCandidates.begin();

            enum BaseType resolved = (left->baseType && right->baseType);
            node.baseType = ResolveTypes::transformBaseType(resolved, 
                                                node.location);

            if (node.baseType != BASE_TYPE_RANGE_INT) {
                  CompileError *ce = new CompileError(node, 
                        "Not a discrete type in discrete range.");
                  ErrorRegistry::addError(ce);
            }

            // if backup is empty, we'll need to deliver all possible
            // types -> keep types from right hand side.
            if (! backup.empty()) {
                  this->typeCandidates = backup;
            }

            // generate range type
            SubtypeIndication *rangeType 
                        = new SubtypeIndication(
                                    left, 
                                    Location("temporary"));
            rangeType->constraint = &node;
            node.type = rangeType;

            return;
      } else {
            // can this happen? at what place?
            std::cerr << "BOOM: The unexpected happened at " 
                  << node.location << std::endl;

            std::cerr << "left:" << std::endl;
            this->debugPrintTypes(fromT);
            std::cerr << "right: " << std::endl;
            this->debugPrintTypes(this->typeCandidates);
            std::cerr << "wanted: " << std::endl;
            this->debugPrintTypes(backup);
            assert(false);
      }
}

void
00217 ResolveTypes::processDRByName(DiscreteRange &node)
{
      assert(node.rangeName != NULL);
      bool mustSingle = this->typeCandidates.size() == 1;
      node.rangeName->accept(*this);

      if (mustSingle) {
            this->needUniqueType(node);
      }
}

void 
00229 ResolveTypes::visit(VarAssignStat &node)
{
      assert(node.target);
      assert(node.source);

      // traverse to target
      this->typeCandidates.clear();
      node.target->accept(*this);
      if (! this->needUniqueType(node)) {
            return;
      }

      // pin down type of target
      node.target->accept(*this);
      assert(this->typeCandidates.size() == 1);

      //traverse to source
      node.source->accept(*this);
      if (! this->needUniqueType(node)) {
            return;
      }
}

void
00253 ResolveTypes::visit(SigAssignStat &node)
{
      assert(node.target);
      assert(node.waveForm);

      // traverse to target
      this->typeCandidates.clear();
      node.target->accept(*this);

      if (! this->needUniqueType(node)) {
            return;
      }

      // pin down type of target
      node.target->accept(*this);
      assert(this->typeCandidates.size() == 1);

      typeSetT backup = this->typeCandidates;
      //traverse to every element of the waveform.
      for (std::list<WaveFormElem*>::const_iterator i = 
            node.waveForm->begin();
            i != node.waveForm->end(); i++) {

            this->typeCandidates = backup;
            (*i)->accept(*this);

            if (! this->needUniqueType(node)) {
                  return;
            }
      }
}

void
00286 ResolveTypes::visit(WaveFormElem &node)
{
      assert(node.value != NULL);
      node.value->accept(*this);
      
      if (node.delay != NULL) {
            typeSetT backup = this->typeCandidates;
            this->typeCandidates.clear();

            const TypeDeclaration *t = 
                  this->symbolTable.getStdStandardType("time");
            this->typeCandidates.insert(t);
            node.delay->accept(*this);
            this->needUniqueType(*node.delay);

            this->typeCandidates = backup;
      }
}

void
00306 ResolveTypes::visit(SimpleName &node)
{
      bool mustSingle = (this->typeCandidates.size() == 1);

      SymbolFilter tf = SymbolFilter(node.candidates, this->typeCandidates);
      tf.apply();

      if (mustSingle) {
            this->needUniqueType(node);
      } else {
            this->needNotEmpty(node.location);
      }
}

void
00321 ResolveTypes::visit(SelectedName &node)
{
      /** nested class to transform a record element symbol to the 
       *  parent record type.
       */
      class SelectionFilter : public SymbolFilter {
      public:
            /** c'tor
             *  @param cands candidate symbols
             *  @param wantTypes list of wanted types
             */
            SelectionFilter(std::list<Symbol*> &cands,
                        typeSetT &wantTypes
                        ) : SymbolFilter (cands, wantTypes) {}
      private:
            /** operation to transform an element to a parent record type.
             *  @param element RecordTypeElement symbol
             *  @return parent RecordType.
             */
            virtual const TypeDeclaration*
            operator()(Symbol *element) const {

                  assert(element);
                  if (element->type != SYMBOL_ELEMENT) {
                        return NULL;
                  }

                  RecordTypeElement *rel = 
                        dynamic_cast<RecordTypeElement*>(
                                    &(element->declaration));
                  assert(rel);
                  assert(rel->parent);
                  return rel->parent;
            }

      };

      assert(node.prefix);
      assert(node.name);

#if SELECTION_DEBUG
      std::cerr << "Selection enter (prefix at " << node.prefix->location
            << "=" 
            << node.prefix << ")" 
            << std::endl;
      ResolveTypes::debugPrintTypes(this->typeCandidates);
#endif

      bool mustSingle = (this->typeCandidates.size() == 1);

      // 1. filter on current types.
      SymbolFilter tf = SymbolFilter(node.candidates, this->typeCandidates);
      tf.apply();

#if SELECTION_DEBUG
      std::cerr << "Selection after SymbolFilter" << std::endl;
      ResolveTypes::debugPrintTypes(this->typeCandidates);
#endif

      size_t numSyms = node.candidates.size();

      typeSetT backup = this->typeCandidates;
      this->typeCandidates.clear();

      // build list of possible record types of prefix
      SelectionFilter sf = SelectionFilter(node.candidates, 
                                    this->typeCandidates);
      sf.apply();

#if SELECTION_DEBUG
      std::cerr << "prefix candidates (before traversal)" << std::endl;
      ResolveTypes::debugPrintTypes(this->typeCandidates);
#endif

      // traverse to prefix
      node.prefix->accept(*this);

#if SELECTION_DEBUG
      std::cerr << "prefix candidates (after traversal)" << std::endl;
      ResolveTypes::debugPrintTypes(this->typeCandidates);
#endif

      // prefix types were filtered, filter out candidate symbols which
      // still match.
      sf.apply();

      this->needNotEmpty(node.prefix->location);

      // restore old candidates 
      this->typeCandidates = backup;
      if (node.candidates.size() != numSyms) {
#if SELECTION_DEBUG
            std::cerr << "Selection: again" << std::endl;
#endif
            // candidates got reduced by the SelectionFilter. Filter by
            // wanted types again.
            tf.apply();

            // apply types to prefix
            backup = this->typeCandidates;
            this->typeCandidates.clear();
            // regenerate the only possible type the prefix may take
            sf.apply();
            // it *must* be one
            assert(this->typeCandidates.size() == 1);
            // apply it to the prefix
            node.prefix->accept(*this);

            this->typeCandidates = backup;
      }

      if (mustSingle) {
            this->needUniqueType(node);
      } else {
            this->needNotEmpty(node.location);
      }
}

void
00440 ResolveTypes::visit(AttributeName &node)
{
      typedef void (ResolveTypes::*rtANMethT)(AttributeName &);

      std::map<std::string, rtANMethT> attrCals;
      attrCals["range"] = &ResolveTypes::processRangeAttr;
      attrCals["left"] = &ResolveTypes::processLeftAttr;
      attrCals["right"] = &ResolveTypes::processRightAttr;
      // TODO

      std::map<std::string, rtANMethT>::iterator i = 
            attrCals.find(*node.name);

      if (i == attrCals.end()) {
            std::cerr << "cannot find attribute <" << *node.name
                  << ">." << std::endl;
            assert(false);
      }
      
      (this->*(i->second))(node);
}

void
00463 ResolveTypes::processRangeAttr(AttributeName &node)
{
      assert(node.prefix != NULL);

      bool mustSingle = this->typeCandidates.size() == 1;
      typeSetT backup = this->typeCandidates;

      this->typeCandidates.clear();
      node.prefix->accept(*this);
      IndexTypeFilter itf = 
            IndexTypeFilter(this->typeCandidates, backup, 1);
      itf.apply();

      if (mustSingle) {
            bool res = this->needUniqueType(node);
            if (res) {
                  switch ((*backup.begin())->baseType) {
                  case BASE_TYPE_INTEGER:
                        node.baseType = BASE_TYPE_RANGE_INT;
                        break;

                  case BASE_TYPE_REAL:
                        node.baseType = BASE_TYPE_RANGE_REAL;
                        break;

                  default:
                        assert(false);
                  }

                  // pin down type...
                  node.prefix->accept(*this);
            }
      }
      this->typeCandidates = backup;
}

void
00500 ResolveTypes::processLeftAttr(AttributeName &node)
{
      assert(false);
}

void
00506 ResolveTypes::processRightAttr(AttributeName &node)
{
      assert(false);
}

void
00512 ResolveTypes::visit(FunctionCall &node)
{
      /** nested filter class to filter based on the return type and on
       *  the number of arguments.
       */
      class ReturnValueFilter : public SymbolFilter {
      public:
            /** c'tor
             *  @param cands candidate symbols of functions
             *  @param wantTypes wanted types (return types)
             *  @param argc number of arguments given.
             */
            ReturnValueFilter(
                  std::list<Symbol*> &cands,
                  typeSetT &wantTypes
                  ) :   SymbolFilter(cands, wantTypes) {}
      private:
            /** resolve a symbol to the return type of a function
             *  call.
             *  @param element symbol representing a Function.
             *  @return returnType of the declaration.
             */
            virtual const TypeDeclaration*
            operator()(Symbol *element) const {
                  if (element->type != SYMBOL_FUNCTION) {
                        return NULL;
                  }

                  FunctionDeclaration *decl = 
                        dynamic_cast<FunctionDeclaration*>(
                                          &(element->declaration)
                        );
                  assert(decl);
                  assert(decl->returnType);
                  assert(decl->returnType->declaration);

                  return decl->returnType->declaration;
            }
      };

      assert(node.subprog);
      assert(node.arguments);

      bool mustSingle = (this->typeCandidates.size() == 1);

      ReturnValueFilter rf = ReturnValueFilter(node.subprog->candidates,
                                    this->typeCandidates);
      rf.apply();

      // minor check that no positional arguments are present after named
      // arguments (TODO should go somewhere else)
      // FIXME assert's, that no named areguments are present at all,
      // since these are currently not supported.
      bool positional = true;
      for (std::list<AssociationElement*>::const_iterator i = 
            node.arguments->begin(); i != node.arguments->end(); i++) {

            if ((*i)->formal) {
                  positional = false;
                  assert(false); //named arguments not yet supported.
            } else {
                  if (! positional) {
                        CompileError *ce = new CompileError(
                                    (*i)->formal->location,
                                    "Positional argument after "
                                    "named argument");
                        ErrorRegistry::addError(ce);
                        return;
                  }
            }
      }

      typeSetT backup = this->typeCandidates;
      this->typeCandidates.clear();
      
      this->processSubprogCall(node, mustSingle);
      // filter again, to reduce return types.
      this->typeCandidates = backup;
      rf.apply();

      if (mustSingle && node.subprog->candidates.size() == 1) {
            node.definition = 
                  dynamic_cast<FunctionDeclaration*>(
                        &node.subprog->candidates.front()->declaration
                        );
            assert(node.definition != NULL);
      }

      if (mustSingle) {
            this->needUniqueType(node);
      }
}

void
00606 ResolveTypes::visit(ProcCallStat &node)
{
      assert(node.subprog);
      assert(node.arguments);

      this->typeCandidates.clear();
      this->processSubprogCall(node, true);
      if (node.subprog->candidates.size() != 1) {
            // error reported from AssociationElement list already
            return;
      }

      Symbol *sym = node.subprog->candidates.front();
      node.definition = 
            dynamic_cast<ProcedureDeclaration*>(&sym->declaration);
}

void
00624 ResolveTypes::visit(SubtypeIndication &node)
{
      this->typeCandidates.clear();
      // ignore typeName, that's already handled in c'tor
      
      // FIXME that's too easy... constraint must be of a
      //       specific type!
      if (node.constraint != NULL) {
            node.constraint->accept(*this);
            this->typeCandidates.clear();
      }

      // FIXME resolution function
      if (node.indexConstraint == NULL) {
            return;
      }

      /* base must be unconstraint array */
      const UnconstrainedArrayType *base = 
            dynamic_cast<const UnconstrainedArrayType*>(
                        this->findBaseType(node.declaration));
      assert(base != NULL);
      assert(base->indexTypes != NULL);

      if (node.indexConstraint->size() != base->indexTypes->size()) {
            CompileError *ce = new CompileError(node, 
                  "wrong number of indices for index constraint.");
            ErrorRegistry::addError(ce);
            return;
      }

      std::list<TypeDeclaration*>::iterator j = base->indexTypes->begin();
      for (std::list<DiscreteRange*>::iterator i = 
            node.indexConstraint->begin();
            i != node.indexConstraint->end(); i++, j++) {

            this->typeCandidates.insert(*j);
            (*i)->accept(*this);
            this->typeCandidates.clear();
      }
}


template <typename T>
void
00669 ResolveTypes::processSubprogCall(T &node, bool mustSingle)
{
      assert(node.arguments);
      assert(node.subprog);

      /* FIXME this is not quite right yet.
       * Example: 
       *    x : integer;
       *
       *    if 2 = x then
       *    ...
       *
       * Currently, 2 as first operand will resolve = uniquely to
       * "="(anon, anon: universal_integer);
       *
       * Hence it will result in a type error, because x is of a different
       * type (and as non-universal type not convertible).
       */

      if (mustSingle) {
            // do a first trial pass to perform overload resolution
            this->processSubprogCall(node, false);
            // now each argument *must* result in a single type!
            if (1 < node.subprog->candidates.size()) {
                  std::string msg = "Ambiguous subprogram call of <";
                  msg += *node.subprog->name + ">. ";

#if FUNCCALLS_DEBUG
                  std::cerr << "TYPE ERROR: " << node << std::endl;
#endif /* FUNCCALLS_DEBUG */

                  CompileError *ce = new CompileError(node, msg);
                  ErrorRegistry::addError(ce);
                  return;
            }
      }

      //! filter out symbols by number of arguments.
      /** FIXME currently this filter relies on no formal parts being 
       *        present, because these could indicate individual 
       *        association. 
       *        For individual association, one approach would be to 
       *        flatten every type (which has the caveat, that conversion
       *        functions cannot be handled that way, since these need to
       *        be done on the complete composite type, if no individual
       *        association is used) and check again.
       *        Another possible approach, would be to count the different
       *        formal parts with different names.
       *        This filter also doesn't take into account yet, that 
       *        formal parts are a means of reducing the candidates as 
       *        well (e.g. if a formal part with given name is not present
       *        for a candidate).
       */    
      class ArgcFilter {
      public:
            /** c'tor
             *  @param cands candidate symbols of callable's
             *  @param args current argument list
             */
            ArgcFilter(std::list<Symbol*> &cands,
                        const std::list<AssociationElement*> &args
                        ) : sc(cands), a(args) {}

            /** apply the filter */
            void apply(void) {
                  for (std::list<Symbol*>::iterator i = 
                        this->sc.begin(); i != this->sc.end();
                        /* nothing */) {

                        //FIXME see long comment above

                        Callable *c = 
                              dynamic_cast<Callable*>(
                                          &(*i)->declaration);

                        if (c == NULL) {
                              i = this->sc.erase(i);
                              continue;
                        }

                        if (   (c->arguments == NULL) 
                            && this->a.empty()) {

                              i++;
                              continue;
                        } 

                        if (c->arguments == NULL) {
                              // args not empty
                              i = this->sc.erase(i);
                              continue;
                        }

                        if (c->arguments->size() != this->a.size()) {
                              i = this->sc.erase(i);
                              continue;
                        }
                        i++;
                  }
            }
      private:
            //!candidates
            std::list<Symbol*> &sc;
            //!arguments
            const std::list<AssociationElement*> &a;
      };

      // filter on number of arguments
      ArgcFilter argcf = ArgcFilter(
                  node.subprog->candidates,
                  *node.arguments);
      argcf.apply();

      ProjectPositionalArg paf = ProjectPositionalArg(
                              node.subprog->candidates,
                              this->typeCandidates,
                              0);

      for (std::list<AssociationElement*>::const_iterator i = 
            node.arguments->begin(); i != node.arguments->end(); 
            i++, paf.position++) {

            //TODO: named arguments.
            assert((*i)->formal == NULL);
            assert((*i)->actual); /* FIXME open associations */
            
            this->typeCandidates.clear();
            // fetch *all* possible types into typeCandidates.
            paf.apply();

#if FUNCCALLS_DEBUG
            std::cerr << (*i)->location << ": " << *i 
                  << " all possible types " << std::endl;
            this->debugPrintTypes(this->typeCandidates);
#endif /* FUNCCALLS_DEBUG */

            // traverse to actual part
            (*i)->accept(*this);

#if FUNCCALLS_DEBUG
            std::cerr << (*i)->location << ": " << *i 
                  << " reduced set" << std::endl;
            this->debugPrintTypes(this->typeCandidates);
#endif /* FUNCCALLS_DEBUG */

            // now typeCandidates contains the set of possbile types, that
            // can be matched by the argument. filter the possible types
            // again (actually possible types are reduced not by 
            // actual types, but rather by a reduced set of possible types).
            paf.apply();
      }

      this->typeCandidates.clear();
}

void
00825 ResolveTypes::visit(Subscript &node)
{
      // FIXME 6.4 (and 10.5) make it not explicitely clear, if the 
      //       index constraints may be used to eliminate possibile
      //       interpretions in the first place.
      //
      //       Is this valid?
      //
      //     type foo is range 1 to 10;
      //     type bar is range 1 to 20;
      //       type x is array(foo) of integer;
      //       type y is array(bar) of integer;
      //
      //       function f() return x;
      //       function f() return y;
      //
      //       var a : foo;
      //       var b : bar;
      //       var i : integer;
      //
      //       a := f(a);
      //       a := f(b);
      //
      // IMHO the only rule here would be that the prefix must be an array
      //      type, so wether it has the correct number of indices
      //      and wether the index types are set correct shouldn't matter.
      //
      // The current implementation eliminates candidates of f via 
      // index types though.
      assert(node.source != NULL);
      assert(node.indices != NULL);

      typeSetT wantTypes = this->typeCandidates;
      bool mustSingle = wantTypes.size() == 1;
      this->typeCandidates.clear();

      node.source->accept(*this);

      SubscriptFilter sf = SubscriptFilter(this->typeCandidates, wantTypes);
      sf.apply();

      typeSetT backup = this->typeCandidates;
      if (! mustSingle) {
            // fetch index types
            unsigned int nIdx = 1;
            for (std::list<Expression*>::iterator i = node.indices->begin();
                  i != node.indices->end(); i++) {
                  
                  this->typeCandidates.clear();

                  IndexTypeFilter itf = 
                        IndexTypeFilter(backup, 
                                    this->typeCandidates, nIdx);
                  itf.apply();
                  (*i)->accept(*this);

                  nIdx++;
            }
      }
      this->typeCandidates = backup;

      if (mustSingle) {
            // pin down source
            node.source->accept(*this);

            // and pin down index types
            unsigned int nIdx = 1;
            for (std::list<Expression*>::iterator i = node.indices->begin();
                  i != node.indices->end(); i++) {

                  this->typeCandidates.clear();
                  IndexTypeFilter itf = 
                        IndexTypeFilter(backup, 
                                    this->typeCandidates, nIdx);
                  itf.apply();
                  (*i)->accept(*this);

                  if (! this->needUniqueType(**i)) {
                        this->typeCandidates = backup;
                        return;
                  }
                  nIdx++;
            }
      }

      this->typeCandidates = wantTypes;
      if (mustSingle) {
            bool ret = this->needUniqueType(node);
            if (! ret) {
                  return;
            }

            // check number of indices
            const TypeDeclaration *d = 
                  ResolveTypes::findBaseType(node.source->type);
            const UnconstrainedArrayType *ua = 
                  dynamic_cast<const UnconstrainedArrayType*>(d);
            assert(ua != NULL);
            if (node.indices->size() < ua->indexTypes->size()) {
                  CompileError *ce = 
                        new CompileError(node, "Too few indices");
                  ErrorRegistry::addError(ce);
            }

            if (node.indices->size() > ua->indexTypes->size()) {
                  CompileError *ce = 
                        new CompileError(node, "Too many indices");
                  ErrorRegistry::addError(ce);
            }

      } else {
            this->needNotEmpty(node.location);
      }
}

void
00941 ResolveTypes::visit(ConstInteger &node)
{
      if (node.physUnit != NULL) {
            // unit is a physical type. Let SimpleName handle this.
            node.physUnit->accept(*this);
            node.type = node.physUnit->type;
            return;
      }

      const TypeDeclaration *uInt = 
            this->symbolTable.getStdStandardType("__universal_integer__");
      assert(uInt);
      this->processUniversal(node, uInt, BASE_TYPE_INTEGER);
}

void
00957 ResolveTypes::visit(ConstReal &node)
{
      const TypeDeclaration *uReal = 
            this->symbolTable.getStdStandardType("__universal_real__");
      assert(uReal);
      this->processUniversal(node, uReal, BASE_TYPE_REAL);
}

void
00966 ResolveTypes::visit(Aggregate &node)
{
      //FIXME handles only array aggregates atm.
      assert(node.associations != NULL);
      bool isArray = false;

      for (typeSetT::iterator i = this->typeCandidates.begin(); 
            i != this->typeCandidates.end(); /* nothing */) {

            switch((*i)->baseType) {
            case BASE_TYPE_ARRAY:
                  isArray = true;
                  i++;
                  continue;
            case BASE_TYPE_RECORD:
                  isArray = false;
                  i++;
                  continue;
            default:
                  /* fall through */
                  break;
            }

            // not a composite type, remove.
            typeSetT::iterator j = i;
            i++;
            this->typeCandidates.erase(j);
      }

      if (! this->needUniqueType(node)) {
            return;
      }

      // typeCandidates contain exactly one type
      if (isArray) {
            this->processArrayAgg(node);
            node.baseType = BASE_TYPE_ARRAY;
            return;
      } 

      node.baseType = BASE_TYPE_RECORD;
      // TODO record Aggregates
      return;
}

void
01012 ResolveTypes::processArrayAgg(Aggregate &node)
{
      // must have been filtered by caller.
      assert(this->typeCandidates.size() == 1);

      // determine subscripted type
      const TypeDeclaration *wanted = *(this->typeCandidates.begin());

      for (std::list<ElementAssociation*>::const_iterator i = 
            node.associations->begin(); i != node.associations->end();
            i++) {

            this->typeCandidates.clear();
            this->typeCandidates.insert(wanted);
            // don't dispatch, call directly instead.
            this->processArrayAssoc(**i);
      }

      // restore candidates
      this->typeCandidates.clear();
      this->typeCandidates.insert(wanted);
}

void
01036 ResolveTypes::visit(ElementAssociation &node)
{
      assert(false); // use direct calls instead of dispatching.
}

void
01042 ResolveTypes::visit(ReturnStat &node)
{
      if (node.result == NULL) {
            // no return expression, break early.
            return;
      }

      // determine return type
      // FIXME catch error that result is present, but 
      //       node refers to a Procedure
      LookupTypes lat = LookupTypes(false, false);

      assert(node.enclosingSubprog != NULL);
      node.enclosingSubprog->accept(lat);
      assert(lat.declaration != NULL);

      this->typeCandidates.clear();
      this->typeCandidates.insert(lat.declaration);
      
      // traverse to result expression (will report errors, since
      // there is only a single type in wantTypes)
      node.result->accept(*this);
      this->typeCandidates.clear();
}

void
01068 ResolveTypes::visit(Process &node)
{
      if (node.sensitivityList != NULL) {
            for (std::list<Name*>::iterator i = 
                  node.sensitivityList->begin();
                  i != node.sensitivityList->end(); i++) {

                  this->typeCandidates.clear();
                  (*i)->accept(*this);
                  if (! this->needUniqueType(**i)) {
                        continue;
                  }
                  
                  (*i)->accept(*this);
                  this->needUniqueType(**i);
            }
      }

      if (node.declarations != NULL) {
            this->listTraverse(*node.declarations);
      }
      this->typeCandidates.clear();

      if (node.seqStats != NULL) {
            this->listTraverse(*node.seqStats);
      }
}

void
01097 ResolveTypes::processArrayAssoc(ElementAssociation &node)
{
      // need exactly one candidate. If that's not true, Aggregate should
      // have reported an error and not called this method.
      assert(this->typeCandidates.size() == 1); 

      if (node.choices != NULL) {
            // determine possible index types.
            typeSetT backup = this->typeCandidates;
            this->typeCandidates.clear();
            IndexTypeFilter itf = IndexTypeFilter(backup, 
                                          this->typeCandidates,
                                          1);
            itf.apply();
            typeSetT wantedIndexTypes = this->typeCandidates;

            for (std::list<Expression*>::const_iterator i = 
                  node.choices->begin();
                  i != node.choices->end(); i++) {

                  this->typeCandidates = wantedIndexTypes;
                  (*i)->accept(*this);
                  // check if index types match.
                  itf.apply();
                  if (! this->needUniqueType(node)) {
                        // type error, bail out immediately
                        return;
                  }

                  assert((*i)->type != NULL);
            }
            this->typeCandidates = backup;
      }

      assert(node.actual != NULL);
      // getting tricky: 
      // * if it's a multidimensional array, remove the first index and 
      //   traverse to actual.
      // * otherwise determine the element type and traverse to actual.
      //
      // Examples: (0 => (0 => '1', 1 => '0'), 1 to 3 => (others => '1'))
      //           is valid for
      //           array(0 to 3, 0 to 1) of character;
      //           *and*
      //           at : array(0 to 1) of character;
      //           array(0 to 3) of at;
      const TypeDeclaration *wanted = *this->typeCandidates.begin();
      const TypeDeclaration *needed = 
            ResolveTypes::subscribedType(*wanted, 1, node.location);

      // traverse to actual
      this->typeCandidates.clear();
      this->typeCandidates.insert(needed);
      node.actual->accept(*this);
      this->typeCandidates.clear();
      this->typeCandidates.insert(wanted);
}

const TypeDeclaration *
01156 ResolveTypes::subscribedType(
      const TypeDeclaration &array, 
      unsigned int nIdx,
      Location loc
)
{
      assert(array.baseType == BASE_TYPE_ARRAY);
      std::list<DiscreteRange*> idxConstraint = std::list<DiscreteRange*>();
      const UnconstrainedArrayType *uArr = 
            ResolveTypes::pickupIndexConstraint(&array, idxConstraint);

      assert(uArr->indexTypes != NULL);

      if (uArr->indexTypes->size() < nIdx) {
            // FIXME: issue error here.
            assert(false);
      }

      if (uArr->indexTypes->size() == nIdx) {
            // subscription to base type.
            return uArr->containerType;
      }

      // partial subscription. strip off first nIdx indices.
      std::list<TypeDeclaration*>::iterator i = uArr->indexTypes->begin();
      for (unsigned int c = nIdx; c > 0; c--) {
            i++;
      }

      std::list<TypeDeclaration*> *shiftIndices = 
                              new std::list<TypeDeclaration*>();

      shiftIndices->insert(shiftIndices->end(), i, uArr->indexTypes->end());

      // that's the new anonymous base type.
      UnconstrainedArrayType *ua = new UnconstrainedArrayType(
                  new std::string("__anonymous__"),
                  shiftIndices,
                  uArr->containerType,
                  loc);

      if (idxConstraint.empty()) {
            // must have been an Unconstraint array already.
            return ua;
      }

      // FIXME must be checked somewhere (hello parser?)
      assert(idxConstraint.size() == uArr->indexTypes->size());
      // strip off nIdx indices from indexConstraint as well.
      for (std::list<DiscreteRange*>::iterator j = idxConstraint.begin();
            nIdx > 0; nIdx--) {

            assert(j != idxConstraint.end());
            j = idxConstraint.erase(j);
      }

      SubtypeIndication *si = new SubtypeIndication(ua, loc);
      si->indexConstraint = new std::list<DiscreteRange*>(idxConstraint);

      return si;
}


void
01220 ResolveTypes::visit(Others &node)
{
      if (this->typeCandidates.size() == 1) {
            this->needUniqueType(node);
      }

      // otherwise others does not affect type candidates.
}

void
01230 ResolveTypes::visit(Slice &node)
{
      assert(node.source);
#if SLICE_DEBUG
      std::cerr << "Slice before source" << std::endl;
      ResolveTypes::debugPrintTypes(this->typeCandidates);
#endif
      node.source->accept(*this);

#if SLICE_DEBUG
      std::cerr << "Slice after source" << std::endl;
      ResolveTypes::debugPrintTypes(this->typeCandidates);
#endif

      typeSetT backup = this->typeCandidates;
      this->typeCandidates.clear();

      // determine index types and store these in typeCandidates
      IndexTypeFilter itf = 
            IndexTypeFilter(backup, this->typeCandidates, 1);
      itf.apply();
#if SLICE_DEBUG
      std::cerr << "#indexTypes for " << *node.source << "=" 
            << this->typeCandidates.size() << std::endl;
      std::cerr << "#source types=" << backup.size() << std::endl;
#endif

      // traverse to range and filter out types
      assert(node.range);
      node.range->accept(*this);
      itf.apply();
      this->typeCandidates = backup;

      this->needUniqueType(node);
}

void
01267 ResolveTypes::visit(TemporaryName &node)
{
      // only traverse to prefix, do nothing else
      assert(node.prefix != NULL);
      node.prefix->accept(*this);

      // set the type in case it's known
      if (this->typeCandidates.size() == 1) {
            this->needUniqueType(node);
      }
}

void
01280 ResolveTypes::visit(AttributeSpecification &node)
{
      this->typeCandidates.clear();
      assert(node.declaration != NULL);
      assert(node.declaration->type != NULL);

      this->typeCandidates.insert(node.declaration->type);

      assert(node.init != NULL);
      node.init->accept(*this);

      this->needUniqueType(node);
      this->typeCandidates.clear();
}

void
01296 ResolveTypes::processUniversal(
      Expression &node,
      const TypeDeclaration *directMatch,
      enum BaseType icCompatible
)
{
      assert(directMatch != NULL);

      // no type candidates -> put directMatch (universal_int, U.real)
      // in there.
      // (implicit conversions are only allowed, if the wanted type
      // is known, LRM 7.3.5).
      if (this->typeCandidates.empty()) {
            this->typeCandidates.insert(directMatch);
            this->needUniqueType(node);
            return;
      }

      bool mustSingle = (this->typeCandidates.size() == 1);

      // check if there is a direct match for __universal_integer__
      typeSetT backup = this->typeCandidates;
      for (typeSetT::iterator i = backup.begin(); i != backup.end(); 
            /* nothing */) {

            if (! ResolveTypes::baseTypeEqual(**i, *directMatch)) {
                  typeSetT::iterator j = i;
                  i++;
                  backup.erase(j);
                  continue;
            }

            i++;
      }

      if (! backup.empty()) {
            // direct match against universal_integer found. return this.
            this->typeCandidates = backup;
            this->needUniqueType(node);
            return;
      }

      // node is of type (convertible) universal_integer. Filter out all 
      // types that are not integer based.
      for (typeSetT::iterator i = this->typeCandidates.begin(); 
            i != this->typeCandidates.end(); /* nothing */) {

            if ((*i)->baseType != icCompatible) {
                  typeSetT::iterator j = i;
                  i++;
                  this->typeCandidates.erase(j);
                  continue;
            }
            i++;
      }

      if (mustSingle) {
            this->needUniqueType(node);
      }
}

void
01358 ResolveTypes::visit(RangeConstraintType &node)
{
      this->processConstraintType(node);
}

void
01364 ResolveTypes::visit(PhysicalType &node)
{
      this->processConstraintType(node);
      if (node.baseType != BASE_TYPE_INTEGER) {
            node.baseType = BASE_TYPE_INTEGER;
            CompileError *err = new CompileError(node, 
                        "Constraint must be an integral type.");
            ErrorRegistry::addError(err);
      }
}

void
01376 ResolveTypes::visit(RecordType &node)
{
      // nothing to do, *don't* traverse to elements!
}

void
01382 ResolveTypes::visit(FunctionDeclaration &node)
{
      // do *not* traverse to returnType
      this->process(node);
}

void
01389 ResolveTypes::visit(ForLoopStat &node)
{
      // set type declaration of loop parameter specification from
      // discrete range.
      this->typeCandidates.clear();
      assert(node.range != NULL);
      node.range->accept(*this);

      bool ret = this->needUniqueType(node);
      if (! ret) {
            return;
      }

      const TypeDeclaration *t = *this->typeCandidates.begin();
      if (t->isUniversal) {
            t = this->symbolTable.getStdStandardType("integer");
            this->typeCandidates.clear();
            this->typeCandidates.insert(t);
      }

      // actually pin down type
      node.range->accept(*this);

      assert(node.loopVariable != NULL);
      assert(! this->typeCandidates.empty());
      t = *this->typeCandidates.begin();

      // check if it is a discrete type.
      switch (t->baseType) {
      case BASE_TYPE_INTEGER:
            break;
      
      default: {
            CompileError *ce = 
                  new CompileError(*node.range,
                        "For loop parameter must be discrete.");
            ErrorRegistry::addError(ce);
            return;
          }
      }

      node.loopVariable->subtypeIndic = 
            new SubtypeIndication(t, node.loopVariable->location);
      this->typeCandidates.clear();

      // handle seqstats via process.
      this->process(node);
}

void
01439 ResolveTypes::visit(WhileLoopStat &node)
{
      this->typeCandidates.clear();
      // condition must be of type boolean
      const TypeDeclaration *boolean = 
            this->symbolTable.getStdStandardType("boolean");

      assert(boolean != NULL);
      assert(node.condition != NULL);

      this->typeCandidates.insert(boolean);
      node.condition->accept(*this);
      this->typeCandidates.clear();

      if (node.loopStats != NULL) {
            this->listTraverse(*node.loopStats);
      }
}

void
01459 ResolveTypes::visit(AssertStat &node)
{
      this->typeCandidates.clear();

      // condition must be of type boolean
      const TypeDeclaration *boolean = 
            this->symbolTable.getStdStandardType("boolean");

      assert(boolean != NULL);
      assert(node.condition != NULL);

      this->typeCandidates.insert(boolean);
      node.condition->accept(*this);
      this->typeCandidates.clear();

      if (node.report != NULL) {
            // report must be of type string (i.e. compatible to)
            const TypeDeclaration *strT = 
                  this->symbolTable.getStdStandardType("string");
            assert(strT != NULL);
            this->typeCandidates.insert(strT);
            node.report->accept(*this);
            this->typeCandidates.clear();
      }

      if (node.severity != NULL) {
            // report must be of type SEVERITY_LEVEL
            const TypeDeclaration *sevLvl = 
                  this->symbolTable.getStdStandardType(
                                          "severity_level");
            assert(sevLvl != NULL);
            this->typeCandidates.insert(sevLvl);
            node.severity->accept(*this);
            this->typeCandidates.clear();
      }
}

void
01497 ResolveTypes::visit(WaitStat &node)
{
      this->typeCandidates.clear();
      // handle condition
      this->process(node);

      if (node.timeout != NULL) {
            // timeout must be of type "time"
            const TypeDeclaration *time = 
                  this->symbolTable.getStdStandardType("time");
            this->typeCandidates.insert(time);

            node.timeout->accept(*this);
            this->needUniqueType(*node.timeout);
            this->typeCandidates.clear();
      }

      if (node.sensitivities == NULL) {
            return;
      }

      // node.sensitivities != NULL
      for (std::list<Name*>::iterator i = node.sensitivities->begin();
            i != node.sensitivities->end(); i++) {
            
            // TODO (probably in a separate step): the sensitivity list
            //      must consist of solely static names.
            (*i)->accept(*this);
            if (! this->needUniqueType(**i)) {
                  this->typeCandidates.clear();
                  continue;
            }

            (*i)->accept(*this);
            this->needUniqueType(**i);
            this->typeCandidates.clear();
      }
}

void
01537 ResolveTypes::processAlternative(CaseAlternative &node)
{
      assert(node.isVals != NULL);
      assert(node.thenStats != NULL);
      typeSetT backup = this->typeCandidates;
      assert(backup.size() == 1);

      for (std::list<Expression*>::iterator i = node.isVals->begin();
            i != node.isVals->end(); i++) {

            this->typeCandidates = backup;
            (*i)->accept(*this);
            this->needUniqueType(**i);
      }

      this->typeCandidates.clear();
      this->listTraverse(*node.thenStats);
      this->typeCandidates = backup;
}

void
01558 ResolveTypes::visit(CaseStat &node)
{
      assert(node.select != NULL);
      assert(node.alternatives != NULL);

      this->typeCandidates.clear();
      node.select->accept(*this);
      // TODO lrm, 8.8: base type must be discrete, or a one dimensional 
      //                array of a character type.
      bool r = this->needUniqueType(*node.select);
      if (! r) {
            // don't even bother alternatives on type error
            this->typeCandidates.clear();
            return;
      }
      // pin down type
      node.select->accept(*this);
      if (this->typeCandidates.size() != 1) {
            return;
      }

      for (std::list<CaseAlternative*>::iterator i = 
            node.alternatives->begin();
            i != node.alternatives->end(); i++) {

            this->processAlternative(**i);
      }

      this->typeCandidates.clear();
}

template <typename T>
void
01591 ResolveTypes::processConstraintType(T &node)
{
      this->typeCandidates.clear();
      assert(node.constraint != NULL);

      if (node.constraint->rangeName != NULL) {
            // handle these via discrete range.
            node.constraint->accept(*this);
            if (! this->needUniqueType(node)) {
                  return;
            }
            const TypeDeclaration *t = *this->typeCandidates.begin();
            switch(t->baseType) {
            case BASE_TYPE_RANGE_INT:
                  node.baseType = BASE_TYPE_INTEGER;
                  break;
            case BASE_TYPE_RANGE_REAL:
                  node.baseType = BASE_TYPE_RANGE_REAL;
                  break;
            default: {
                  node.baseType = BASE_TYPE_UNSET;
                  CompileError *ce = new CompileError(node.location,
                        "invalid type for constraint.");
                  ErrorRegistry::addError(ce);
                }
                  
            }
            return;
      }


      assert(node.constraint->from != NULL);
      assert(node.constraint->to != NULL);
      node.constraint->from->accept(*this);
      if (! this->needUniqueType(*node.constraint->from)) {
            this->typeCandidates.clear();
            node.baseType = BASE_TYPE_UNSET;
            return;
      }

      // traverse again, to pin down from type
      node.constraint->from->accept(*this);
      // FIXME can this happen?
      assert(this->typeCandidates.size() == 1);

      const TypeDeclaration *t = *this->typeCandidates.begin();
      enum BaseType left = t->baseType;


      this->typeCandidates.clear();
      node.constraint->to->accept(*this);
      if (! this->needUniqueType(*node.constraint->to)) {
            this->typeCandidates.clear();
            node.baseType = BASE_TYPE_UNSET;
            return;
      }

      // traverse again, to pin to from type
      node.constraint->to->accept(*this);
      assert(this->typeCandidates.size() == 1);

      // set base type
      t = *this->typeCandidates.begin();
      this->typeCandidates.clear();
      left = left && t->baseType;

      switch(left) {
      case BASE_TYPE_INTEGER:
      case BASE_TYPE_REAL:
            node.baseType = left;
            break;
      default: {
            node.baseType = BASE_TYPE_UNSET;
            CompileError *ce = new CompileError(node.location,
                  "invalid type for constraint.");
            ErrorRegistry::addError(ce);
          }
      }
}

bool
01672 ResolveTypes::baseTypeEqual(
      const TypeDeclaration &t1,
      const TypeDeclaration &t2
)
{
      // determine base types.
      const TypeDeclaration *b1 = ResolveTypes::findBaseType(&t1);
      const TypeDeclaration *b2 = ResolveTypes::findBaseType(&t2); 

      // compare pointer!
      return b1 == b2;
}

const TypeDeclaration*
01686 ResolveTypes::findBaseType(const TypeDeclaration* t)
{
      if (t == NULL) {
            return NULL;
      }

      const SubtypeIndication *s = 
                  dynamic_cast<const SubtypeIndication*>(t);
      if (s == NULL) {
            // not a subtype
            return t;
      }

      // recurse
      assert(s->declaration);
      return ResolveTypes::findBaseType(s->declaration);
}

const UnconstrainedArrayType*
01705 ResolveTypes::pickupIndexConstraint(
      const TypeDeclaration *constrainedArray,
      std::list<DiscreteRange*> &indexConstraint
)
{
      assert(constrainedArray != NULL);
      assert(constrainedArray->baseType == BASE_TYPE_ARRAY);

      const SubtypeIndication *sub = 
            dynamic_cast<const SubtypeIndication*>(constrainedArray);

      if ((sub != NULL) && (sub->indexConstraint != NULL)) {
            indexConstraint.insert(
                  indexConstraint.end(), 
                  sub->indexConstraint->begin(),
                  sub->indexConstraint->end());
      }

      if (sub != NULL) {
            assert(sub->declaration != NULL);
            return ResolveTypes::pickupIndexConstraint(
                                    sub->declaration,
                                    indexConstraint);
      }

      const UnconstrainedArrayType *ua = 
            dynamic_cast<const UnconstrainedArrayType*>(constrainedArray);
      assert(ua != NULL);
      return ua;
}

void
01737 ResolveTypes::process(ValDeclaration& node)
{
      assert(node.subtypeIndic != NULL);
      this->typeCandidates.clear();
      node.subtypeIndic->accept(*this);

      this->typeCandidates.clear();
      if (node.init != NULL) {
            this->typeCandidates.insert(node.subtypeIndic);
            node.init->accept(*this);

            // FIXME with the current type resolution mechanism,
            //       this is a noop! 
            // for arrays, the node's subtype indication may
            // refer to an unonstraint array, and the bounds
            // are defined by the initializer. replace the
            // subtype indication then.
            if (this->needUniqueType(node)) {
                  if (node.init->baseType != BASE_TYPE_ARRAY) {
                        return;
                  }

                  SubtypeIndication *si = 
                        dynamic_cast<SubtypeIndication*>(
                              node.init->type);
                  assert(si != NULL);
                  util::MiscUtil::terminate(node.subtypeIndic);
                  node.subtypeIndic = si;
            }
      }
}

void
01770 ResolveTypes::process(LibUnit &node)
{
      //don't consider use- or library clauses
      //no need to call process here as well.

      //traverse to declarations.
      if (node.declarations != NULL) {
            this->listTraverse(*node.declarations);
      }
}

void
01782 ResolveTypes::process(ConditionedStat &node)
{
      this->process(static_cast<SeqStat&>(node));
      if (node.condition == NULL) {
            return;
      }
      
      // condition must be of type boolean
      const TypeDeclaration *boolean = 
            this->symbolTable.getStdStandardType("boolean");
      
      assert(boolean != NULL);
      this->typeCandidates.insert(boolean);

      node.condition->accept(*this);
      this->typeCandidates.clear();
}

void
01801 ResolveTypes::process(SeqStat &node)
{
      this->typeCandidates.clear();
}

bool
01807 ResolveTypes::needUniqueType(AstNode &node) const
{
      if (this->typeCandidates.size() == 1) {
            return true;
      }

      if (this->typeCandidates.empty()) {
            std::string msg = "Type error for <";
            msg += util::MiscUtil::toString(node);
            msg += ">.";
            CompileError *ce = new CompileError(node, msg);
            ErrorRegistry::addError(ce);
            return false;
      }

      std::string msg = "Ambiguous Types for <";
            msg += util::MiscUtil::toString(node);
            msg += ">.";

      CompileError *ce = new CompileError(node, msg);
      ErrorRegistry::addError(ce);
      return false;
}

bool
01832 ResolveTypes::needUniqueType(Expression &node) const
{
      bool ret = this->needUniqueType(static_cast<AstNode&>(node));
      if (ret) {
            const TypeDeclaration *t = *this->typeCandidates.begin();
            node.type = const_cast<TypeDeclaration*>(t);
            node.baseType = t->baseType;
      }

      return ret;
}

void
01845 ResolveTypes::needNotEmpty(Location loc) 
{
      if (this->typeCandidates.empty()) {
            //FIXME: better error messages
            CompileError *ce = new CompileError(
                              loc, 
                              "Type error.");
            ErrorRegistry::addError(ce);
      }
}

enum BaseType
01857 ResolveTypes::transformBaseType(enum BaseType rangeType, Location loc)
{
      switch(rangeType) {
      case BASE_TYPE_INTEGER:
            return BASE_TYPE_RANGE_INT;
      case BASE_TYPE_REAL:
            return BASE_TYPE_RANGE_REAL;
            break;
      default: {
            CompileError *ce = new CompileError(
                  loc,
                  "Wrong base type for discrete range.");
            ErrorRegistry::addError(ce);
            }
      }

      return BASE_TYPE_UNSET;
}

void
01877 ResolveTypes::debugPrintTypes(const typeSetT &t)
{
      for (typeSetT::const_iterator i = t.begin(); i != t.end(); i++) {
            std::cerr << "\tcand=" << *i << std::endl;
      }
}

DiscreteRange *
01885 ResolveTypes::determineIndexRangeAgg(
      const UnconstrainedArrayType *at,
      const std::list<ElementAssociation *> &assocs
)
{
      universal_integer lowerBound;
      universal_integer upperBound;

      assert(at->indexTypes != NULL);
      // TODO currently only 1-dimensional arrays supported.
      assert(at->indexTypes->size() == 1);

      DiscreteRange *maxBounds = 
            ResolveTypes::findRange(at->indexTypes->front());
      assert(maxBounds != NULL);
      // TODO direction
      assert(maxBounds->direction == DiscreteRange::DIRECTION_UP);

      // start with a NULL range...
      lowerBound = maxBounds->getUpperBound();
      upperBound = maxBounds->getLowerBound();

      if ((! assocs.empty()) && (assocs.front()->choices == NULL)) {
            // positional aggregate. lower bound is indextype'left
            lowerBound = upperBound;
            upperBound = lowerBound + assocs.size() - 1;

            ConstInteger *lb = new ConstInteger(lowerBound,
                                    Location("context"));
            ConstInteger *ub = new ConstInteger(upperBound,
                                    Location("context"));
            return new DiscreteRange(lb, ub, 
                              DiscreteRange::DIRECTION_UP, 
                              Location("context"));
      }

      // aggregate with choices.
      for (std::list<ElementAssociation *>::const_iterator i = 
            assocs.begin(); 
            i != assocs.end(); i++) {

            if ((*i)->choices != NULL) {
                  for (std::list<Expression*>::const_iterator j =
                        (*i)->choices->begin(); 
                        j != (*i)->choices->end();
                        j++) {

                        const ConstInteger *c = 
                              dynamic_cast<const ConstInteger*>(*j);
                        assert(c != NULL);

                        if (c->value < lowerBound) {
                              lowerBound = c->value;
                        }

                        if (c->value > upperBound) {
                              upperBound = c->value;
                        }
                  }
            } else {
                  upperBound++;
            }
      }

      ConstInteger *lb = new ConstInteger(lowerBound, Location("context"));
      ConstInteger *ub = new ConstInteger(upperBound, Location("context"));
      return new DiscreteRange(lb, ub, DiscreteRange::DIRECTION_UP, 
                        Location("context"));
}

DiscreteRange *
01956 ResolveTypes::findRange(const TypeDeclaration *rangeType)
{
      const SubtypeIndication *sub;

      sub = dynamic_cast<const SubtypeIndication *>(rangeType);
      if (sub != NULL) {
            if (sub->constraint != NULL) {
                  return sub->constraint;
            }
            return ResolveTypes::findRange(sub->declaration);
      }

      const RangeConstraintType *base;
      base = dynamic_cast<const RangeConstraintType *>(rangeType);
      assert(base != NULL);
      assert(base->constraint != NULL);

      return base->constraint;
}


template <typename T>
ResolveTypes::TypeFilter<T>::TypeFilter
01979 (
      T &cands,
      typeSetT &wantTypes
) :         candidates(cands),
            wantedTypes(wantTypes)
{
}

const TypeDeclaration*
01988 ResolveTypes::SymbolFilter::operator()(Symbol *element) const
{
      LookupTypes lat = LookupTypes(false, false);
      element->declaration.accept(lat);

      return lat.declaration;
}

template <typename T>
void
01998 ResolveTypes::TypeFilter<T>::apply(void)
{
      bool getAllPossibleTypes = this->wantedTypes.empty();
      typeSetT possibleTypes = typeSetT();

      for (typename T::iterator i = this->candidates.begin();
            i != this->candidates.end(); /* nothing */) {
            
            //determine type declaration via () operator.
            const TypeDeclaration *t = (*this)(*i);

            if (t == NULL) {
                  //operation turned out that candidate not plausible
                  typename T::iterator j = i;
                  i++;
                  this->candidates.erase(j);
                  continue;
            }

            if (getAllPossibleTypes) {
                  // don't perform type checking.
                  possibleTypes.insert(t);
                  i++;
                  continue;
            }

            if (this->checkType(t)) {
                  possibleTypes.insert(t);
                  i++;
                  continue;
            }

            //resulting type not in wanted types.
            typename T::iterator j = i;
            i++;
            this->candidates.erase(j);
      }

      this->wantedTypes = possibleTypes;
}

template <typename T>
bool
02041 ResolveTypes::TypeFilter<T>::checkType(const TypeDeclaration *t) const
{
      assert(t);

      // must have wanted types, otherwise no type checking should be
      // performed but all possible types should get reported.
      assert(! this->wantedTypes.empty());
      
      for (typeSetT::const_iterator i = this->wantedTypes.begin();
            i != this->wantedTypes.end(); i++) {
            
            if (ResolveTypes::baseTypeEqual(**i, *t)) {
                  return true;
            }
      }
      return false;
}

const TypeDeclaration*
02060 ResolveTypes::ProjectPositionalArg::operator()(Symbol* element) const
{
      switch(element->type) {
      case SYMBOL_FUNCTION:
      case SYMBOL_PROCEDURE:
            break;
      default:
            /* only useful for functions/procedures */
            //FIXME: port map/generic map aspects!
            assert(false);
      }

      Callable *c = dynamic_cast<Callable*>(&element->declaration);
      assert(c);
      assert(c->arguments);

      if (c->arguments->size() <= this->position) {
            return NULL;
      }

      std::list<ValDeclaration*>::const_iterator i = c->arguments->begin();
      std::advance(i, this->position);

      const SubtypeIndication *s = (*i)->subtypeIndic;
      return s->declaration;
}

/** resolve the type of the source to a subscribed
 *  type.
 *  @param element source type 
 *  @return subscribed type.
 */
const TypeDeclaration*
02093 ResolveTypes::SubscriptFilter::operator()(
      typeSetT::value_type element
) const 
{

      // not an array?
      if (element->baseType != BASE_TYPE_ARRAY) {
            return NULL;
      }

      const SubtypeIndication *si = 
            dynamic_cast<const SubtypeIndication*>(
                                    element);
      assert(si);
      const UnconstrainedArrayType *ua = 
            dynamic_cast<const UnconstrainedArrayType*>(
                  ResolveTypes::findBaseType(si));

      assert(ua);
      assert(ua->containerType);
      
      return ua->containerType;
}

const TypeDeclaration*
02118 ResolveTypes::IndexTypeFilter::operator()(typeSetT::value_type element) const
{
      if (element->baseType != BASE_TYPE_ARRAY) {
            return NULL;
      }

      const UnconstrainedArrayType *array = 
            dynamic_cast<const UnconstrainedArrayType*>(
                  ResolveTypes::findBaseType(element));
      assert(array != NULL);
      assert(array->indexTypes != NULL);
      if (array->indexTypes->size() < this->nIdx) {
            return NULL;
      }
      
      
      bool found = false;
      std::list<TypeDeclaration*>::const_iterator i = 
                              array->indexTypes->begin();

      for (unsigned int j = 1; i != array->indexTypes->end(); i++, j++) {
            if (this->nIdx <= j) {
                  found = true;
                  break;
            }
      }

      if (found) {
            return *i;
      }
      return NULL;
}

}; /* namespace ast */

Generated by  Doxygen 1.6.0   Back to index