protected void mergeHandler(
      Type type, T store, List<Pair<Type, String>> handlers, Map<String, T> stores) {
    for (Pair<Type, String> p : handlers) {
      Type handler = p.first();

      if (Type.isSubtype(handler, type)) {
        T nstore = propagate(handler, store);
        merge(p.second(), nstore, stores);
        return; // completely subsumed
      } else if (Type.isSubtype(type, handler)) {
        T nstore = propagate(handler, store);
        merge(p.second(), nstore, stores);
        // not completely subsumed
        type = Type.intersect(type, Type.Negation(handler));
      }
    }
  }
  protected T propagate(int start, int end, T store, List<Pair<Type, String>> handlers) {
    for (int i = start; i < end; ++i) {
      Entry entry = block.get(i);
      try {
        Code code = entry.code;

        // First, check for a label which may have incoming information.
        if (code instanceof Code.Label) {
          Code.Label l = (Code.Label) code;
          T tmp = stores.get(l.label);
          if (tmp != null && store != null) {
            store = join(store, tmp);
          } else if (tmp != null) {
            store = tmp;
          }
        }

        T oldStore = store;

        if (store == null) {
          // this indicates dead-code has been reached.
          continue;
        } else if (code instanceof Code.Loop) {
          Code.Loop loop = (Code.Loop) code;
          Block.Entry nEntry = entry;
          int s = i;
          // Note, I could make this more efficient!
          while (++i < block.size()) {
            nEntry = block.get(i);
            if (nEntry.code instanceof Code.Label) {
              Code.Label l = (Code.Label) nEntry.code;
              if (l.label.equals(loop.target)) {
                // end of loop body found
                break;
              }
            }
          }
          store = propagate(s, i, loop, entry, store, handlers);
          continue;
        } else if (code instanceof Code.IfGoto) {
          Code.IfGoto ifgoto = (Code.IfGoto) code;
          Pair<T, T> r = propagate(i, ifgoto, entry, store);
          store = r.second();
          merge(ifgoto.target, r.first(), stores);
        } else if (code instanceof Code.IfType) {
          Code.IfType ifgoto = (Code.IfType) code;
          Pair<T, T> r = propagate(i, ifgoto, entry, store);
          store = r.second();
          merge(ifgoto.target, r.first(), stores);
        } else if (code instanceof Code.Switch) {
          Code.Switch sw = (Code.Switch) code;

          List<T> r = propagate(i, sw, entry, store);

          // assert r.second().size() == nsw.branches.size()
          Code.Switch nsw = (Code.Switch) entry.code;
          for (int j = 0; j != nsw.branches.size(); ++j) {
            String target = nsw.branches.get(j).second();
            T nstore = r.get(j);
            merge(target, nstore, stores);
          }
          merge(sw.defaultTarget, store, stores);
          store = null;
        } else if (code instanceof Code.TryCatch) {
          Code.TryCatch sw = (Code.TryCatch) code;
          int s = i;

          // Note, I could make this more efficient!
          while (++i < block.size()) {
            entry = block.get(i);
            if (entry.code instanceof Code.Label) {
              Code.Label l = (Code.Label) entry.code;
              if (l.label.equals(sw.target)) {
                // end of loop body found
                break;
              }
            }
          }

          ArrayList<Pair<Type, String>> nhandlers = new ArrayList<Pair<Type, String>>(handlers);
          nhandlers.addAll(0, sw.catches);
          store = propagate(s + 1, i, store, nhandlers);
          i = i - 1; // this is necessary since last label of
          // try-catch is first label of catch handler
        } else if (code instanceof Code.Goto) {
          Code.Goto gto = (Code.Goto) entry.code;
          merge(gto.target, store, stores);
          store = null;
        } else {
          // This indicates a sequential statement was encountered.
          store = propagate(i, entry, store);
          if (entry.code instanceof Code.Return || entry.code instanceof Code.Throw) {
            store = null;
          }
        }

        mergeHandlers(i, code, oldStore, handlers, stores);

      } catch (SyntaxError se) {
        throw se;
      } catch (Throwable ex) {
        internalFailure("internal failure", filename, entry, ex);
      }
    }

    return store;
  }