gt: 	TypeVariable parent = typeVariable.ecr();
context: /* Soot - a J*va Optimization Framework
   * Copyright (C) 1997-2000 Etienne Gagnon.  All rights reserved.
   *
   * This library is free software; you can redistribute it and/or
   * modify it under the terms of the GNU Lesser General Public
   * License as published by the Free Software Foundation; either
   * version 2.1 of the License, or (at your option) any later version.
   *
   * This library is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   * Lesser General Public License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public
   * License along with this library; if not, write to the
   * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   * Boston, MA 02111-1307, USA.
   */
  
  /*
   * Modified by the Sable Research Group and others 1997-1999.  
   * See the 'credits' file distributed with Soot for the complete list of
   * contributors.  (Soot is distributed at http://www.sable.mcgill.ca/soot)
   */
  
  
  package soot.jimple.toolkits.typing.integer;
  
  import java.util.*;
  
  /** Represents a type variable. **/
  class TypeVariable implements Comparable<Object>
  {
    private static final boolean DEBUG = false;
  
    private final int id;
    private TypeVariable rep = this;
    private int rank = 0;
  
    private TypeNode approx;
    private TypeNode inv_approx;
    
    private TypeNode type;
  
    private List<TypeVariable> parents = Collections.emptyList();
    private List<TypeVariable> children = Collections.emptyList();
  
    public TypeVariable(int id, TypeResolver resolver)
    {
      this.id = id;
    }
  
    public TypeVariable(int id, TypeResolver resolver, TypeNode type)
    {
      this.id = id;
      this.type = type;
      approx = type;
      inv_approx = type;
    }
  
    public int hashCode()
    {
      if(rep != this)
        {
  	return ecr().hashCode();
        }
     
      return id;
    }
  
    public boolean equals(Object obj)
    {
      if(rep != this)
        {
  	return ecr().equals(obj);
        }
  
      if(obj == null)
        {
  	return false;
        }
  
      if(!obj.getClass().equals(getClass()))
        {
  	return false;
        }
      
      TypeVariable ecr = ((TypeVariable) obj).ecr();
  
      if(ecr != this)
        {
  	return false;
        }
      
      return true;
    }
  
    public int compareTo(Object o)
    {
      if(rep != this)
        {
  	return ecr().compareTo(o);
        }
  
      return id - ((TypeVariable) o).ecr().id;
    }
    
    private TypeVariable ecr()
    {
      if(rep != this)
        {
  	rep = rep.ecr();
        }
  
      return rep;
    }
  
    public TypeVariable union(TypeVariable var) throws TypeException
    {
      if(rep != this)
        {
  	return ecr().union(var);
        }
  
      TypeVariable y = var.ecr();
  
      if(this == y)
        {
  	return this;
        }
      
      if(rank > y.rank)
        {
  	y.rep = this;
  
  	merge(y);
  	y.clear();
  
  	return this;
        }
  
      rep = y;
      if(rank == y.rank)
        {
  	y.rank++;
        }
  
      y.merge(this);
      clear();
  
      return y;
    }
  
    private void clear()
    {
      inv_approx = null;
      approx = null;
      type = null;
      parents = null;
      children = null;
    }
  
    private void merge(TypeVariable var) throws TypeException
    {
      // Merge types
      if(type == null)
        {
  	type = var.type;
        }
      else if(var.type != null)
        {
  	error("Type Error(22): Attempt to merge two types.");
        }
  
      // Merge parents
      {
        Set<TypeVariable> set = new TreeSet<TypeVariable>(parents);
        set.addAll(var.parents);
        set.remove(this);
        parents = Collections.unmodifiableList(new LinkedList<TypeVariable>(set));
      }
  
      // Merge children
      {
        Set<TypeVariable> set = new TreeSet<TypeVariable>(children);
        set.addAll(var.children);
        set.remove(this);
        children = Collections.unmodifiableList(new LinkedList<TypeVariable>(set));
      }
    }
  
    public int id()
    {
      if(rep != this)
        {
  	return ecr().id();
        }
  
      return id;
    }
  
    public void addParent(TypeVariable variable)
    {
      if(rep != this)
        {
  	ecr().addParent(variable);
  	return;
        }
  
      TypeVariable var = variable.ecr();
   
      if(var == this)
        {
  	return;
        }
  
      {
        Set<TypeVariable> set = new TreeSet<TypeVariable>(parents);
        set.add(var);
        parents = Collections.unmodifiableList(new LinkedList<TypeVariable>(set));
      }
      
      {
        Set<TypeVariable> set = new TreeSet<TypeVariable>(var.children);
        set.add(this);
        var.children = Collections.unmodifiableList(new LinkedList<TypeVariable>(set));
      }
    }
  
    public void removeParent(TypeVariable variable)
    {
      if(rep != this)
        {
  	ecr().removeParent(variable);
  	return;
        }
  
      TypeVariable var = variable.ecr();
   
      {
        Set<TypeVariable> set = new TreeSet<TypeVariable>(parents);
        set.remove(var);
        parents = Collections.unmodifiableList(new LinkedList<TypeVariable>(set));
      }
  
      {
        Set<TypeVariable> set = new TreeSet<TypeVariable>(var.children);
        set.remove(this);
        var.children = Collections.unmodifiableList(new LinkedList<TypeVariable>(set));
      }
    }
  
    public void addChild(TypeVariable variable)
    {
      if(rep != this)
        {
  	ecr().addChild(variable);
  	return;
        }
  
      TypeVariable var = variable.ecr();
   
      if(var == this)
        {
  	return;
        }
  
      {
        Set<TypeVariable> set = new TreeSet<TypeVariable>(children);
        set.add(var);
        children = Collections.unmodifiableList(new LinkedList<TypeVariable>(set));
      }
  
      {
        Set<TypeVariable> set = new TreeSet<TypeVariable>(var.parents);
        set.add(this);
        var.parents = Collections.unmodifiableList(new LinkedList<TypeVariable>(set));
      }
    }
  
    public void removeChild(TypeVariable variable)
    {
      if(rep != this)
        {
  	ecr().removeChild(variable);
  	return;
        }
  
      TypeVariable var = variable.ecr();
   
      {
        Set<TypeVariable> set = new TreeSet<TypeVariable>(children);
        set.remove(var);
        children = Collections.unmodifiableList(new LinkedList<TypeVariable>(set));
      }
  
      {
        Set<TypeVariable> set = new TreeSet<TypeVariable>(var.parents);
        set.remove(this);
        var.parents = Collections.unmodifiableList(new LinkedList<TypeVariable>(set));
      }
    }
  
    public List<TypeVariable> parents()
    {
      if(rep != this)
        {
  	return ecr().parents();
        }
      
      return parents;
    }
  
    public List<TypeVariable> children()
    {
      if(rep != this)
        {
  	return ecr().children();
        }
      
      return children;
    }
  
    public TypeNode approx()
    {
      if(rep != this)
        {
  	return ecr().approx();
        }
  
      return approx;
    }
  
    public TypeNode inv_approx()
    {
      if(rep != this)
        {
  	return ecr().inv_approx();
        }
  
      return inv_approx;
    }
  
    public TypeNode type()
    {
      if(rep != this)
        {
  	return ecr().type();
        }
  
      return type;
    }
  
    static void error(String message) throws TypeException
    {
      try
        {
  	throw new TypeException(message);
        }
      catch(TypeException e)
        {
  	if(DEBUG)
  	  {
  	    e.printStackTrace();
  	  }
  	throw e;
        }
    }
  
    /** Computes approximative types.  The work list must be 
     *  initialized with all constant type variables. */
    public static void computeApprox(TreeSet<TypeVariable> workList) throws TypeException
    {
      while(workList.size() > 0)
        {
  	TypeVariable var = workList.first();
  	workList.remove(var);
  
  	var.fixApprox(workList);
        }
    }
  
    public static void computeInvApprox(TreeSet<TypeVariable> workList) throws TypeException
    {
      while(workList.size() > 0)
        {
  	TypeVariable var = workList.first();
  	workList.remove(var);
  
  	var.fixInvApprox(workList);
        }
    }
  
    private void fixApprox(TreeSet<TypeVariable> workList) throws TypeException
    {
      if(rep != this)
        {
  	ecr().fixApprox(workList);
  	return;
        }
  
      for (TypeVariable typeVariable : parents) {
  