static final List<Type> NO_TYPE_ARGS = 
        Collections.<Type>emptyList();     public static void addToIntersection(List<Type> list, 
        Type type, Unit unit) {
    if (type==null || 
            !list.isEmpty() && 
            type.isAnything()) {
        return;
    }
    else if (type.isExactlyNothing()) {
        list.clear();
        list.add(type);
    }
    else if (type.isIntersection()) {
        List<Type> satisfiedTypes = 
                type.getSatisfiedTypes();
        for (int i=0, 
                size=satisfiedTypes.size(); 
                i<size; i++) {
            Type t = satisfiedTypes.get(i);
            addToIntersection(list, t, unit);
        }
    }
    else {
        if (type.isWellDefined()) {
            TypeDeclaration dec = type.getDeclaration();
            for (int i=0; i<list.size(); i++) {
                Type t = list.get(i);
                if (t.isSubtypeOf(type)) {
                    return;
                }
                else if (type.isSubtypeOf(t)) {
                    list.remove(i);
                    i--; // redo this index
                }
                else if (disjoint(type, t, unit)) {
                    list.clear();
                    list.add(unit.getNothingType());
                    return;
                } 
                else {
                    if (type.isClassOrInterface() && 
                        t.isClassOrInterface() && 
                        t.getDeclaration().equals(dec) &&
                            !type.containsUnknowns() &&
                            !t.containsUnknowns()) {
                        //canonicalize a type of form
                        //T<InX,OutX>&T<InY,OutY> to 
                        //T<InX|InY,OutX&OutY>
                        Type pi = 
                                principalInstantiation(
                                        dec, type, t, 
                                        unit);
                        if (!pi.containsUnknowns()) {
                            list.remove(i);
                            list.add(pi);
                            return;
                        }
                    }
                }
            }
            if (list.size()>1) {
                //it is possible to have a type that is
                //a supertype of the intersection, even 
                //though it is not a supertype of any of  
                //the intersected types!
                Type t = canonicalIntersection(list, unit);
                if (type.isSupertypeOf(t)) {
                    return;
                }
            }
            list.add(type);
        }
    }
} public static void addToUnion(List<Type> list, 
        Type pt) {
    if (pt==null || 
            !list.isEmpty() && 
            pt.isExactlyNothing()) {
        return;
    }
    else if (pt.isAnything()) {
        list.clear();
        list.add(pt);
    }
    else if (pt.isUnion()) {
        List<Type> caseTypes = 
                pt.getCaseTypes();
        for ( int i=0, size=caseTypes.size(); 
                i<size; i++ ) {
            Type t = caseTypes.get(i);
            addToUnion(list, t.substitute(pt));
        }
    }
    else if (pt.isWellDefined()) {
        boolean add=true;
        for (int i=0; i<list.size(); i++) {
            Type t = list.get(i);
            if (pt.isSubtypeOf(t)) {
                add=false;
                break;
            }
            else if (pt.isSupertypeOf(t)) {
                list.remove(i);
                i--; // redo this index
            }
        }
        if (add) {
            list.add(pt);
        }
    }
} public static Type appliedType(
        TypeDeclaration declaration, 
        Type typeArgument) {
    if (declaration==null) return null;
    return declaration.appliedType(null, 
            singletonList(typeArgument));
} public static Type canonicalIntersection(
        List<Type> types, Unit unit) {
    if (types.size()==1) {
        return types.get(0);
    }
    IntersectionType it = new IntersectionType(unit);
    it.setSatisfiedTypes(types);
    return it.canonicalize().getType();
} public static Type intersectionType(
        Type lhst, Type rhst, Unit unit) {
    Type simpleIntersection = 
            getSimpleIntersection(lhst, rhst);
    if (simpleIntersection != null) {
        return simpleIntersection;
    }
    List<Type> list = new ArrayList<Type>(2);
    addToIntersection(list, rhst, unit);
    addToIntersection(list, lhst, unit);
    IntersectionType it = new IntersectionType(unit);
    it.setSatisfiedTypes(list);
    return it.canonicalize().getType();
} public static boolean isNameMatching(
        String startingWith, Declaration d) {
    return isNameMatching(startingWith, d.getName());
} public static boolean isOverloadedVersion(Declaration decl) {
    return decl!=null && 
            (decl.isOverloaded() && 
            !decl.isAbstraction());
} public static boolean isToplevelAnonymousClass(Scope s) {
    if (s instanceof Class) {
        Class td = (Class) s;
        return td.isAnonymous() && td.isToplevel();
    }
    else {
        return false;
    }
} public static boolean isToplevelClassConstructor(
        TypeDeclaration td, Declaration dec) {
    return td.isToplevel() && 
            (dec instanceof Constructor ||
            dec instanceof FunctionOrValue && 
            ((FunctionOrValue) dec).getTypeDeclaration() 
                    instanceof Constructor);
} public static Type union(
        List<Type> types, Unit unit) {
    if (types.size()==1) {
        return types.get(0);
    }
    UnionType ut = new UnionType(unit);
    ut.setCaseTypes(types);
    return ut.getType();
} public static Type unionType(
        Type lhst, Type rhst, Unit unit) {
    List<Type> list = new ArrayList<Type>(2);
    addToUnion(list, rhst);
    addToUnion(list, lhst);
    UnionType ut = new UnionType(unit);
    ut.setCaseTypes(list);
    return ut.getType();
} public static final String LANGUAGE_MODULE_NAME = "ceylon.language";
import static com.redhat.ceylon.model.typechecker.model.ModelUtil.NO_TYPE_ARGS;
import static com.redhat.ceylon.model.typechecker.model.ModelUtil.addToIntersection;
import static com.redhat.ceylon.model.typechecker.model.ModelUtil.addToUnion;
import static com.redhat.ceylon.model.typechecker.model.ModelUtil.appliedType;
import static com.redhat.ceylon.model.typechecker.model.ModelUtil.canonicalIntersection;
import static com.redhat.ceylon.model.typechecker.model.ModelUtil.intersectionType;
import static com.redhat.ceylon.model.typechecker.model.ModelUtil.isNameMatching;
import static com.redhat.ceylon.model.typechecker.model.ModelUtil.isOverloadedVersion;
import static com.redhat.ceylon.model.typechecker.model.ModelUtil.isToplevelAnonymousClass;
import static com.redhat.ceylon.model.typechecker.model.ModelUtil.isToplevelClassConstructor;
import static com.redhat.ceylon.model.typechecker.model.ModelUtil.union;
import static com.redhat.ceylon.model.typechecker.model.ModelUtil.unionType;
import static com.redhat.ceylon.model.typechecker.model.Module.LANGUAGE_MODULE_NAME;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.TreeMap;
import com.redhat.ceylon.model.typechecker.context.TypeCache;
    
    public TypeDeclaration getFloatDeclaration() {
        return (TypeDeclaration) getLanguageModuleDeclaration("Float");
    }
    
    public TypeDeclaration getIntegerDeclaration() {
        return (TypeDeclaration) getLanguageModuleDeclaration("Integer");
    }
    
    public TypeDeclaration getCharacterDeclaration() {
        return (TypeDeclaration) getLanguageModuleDeclaration("Character");
    }
    
    public TypeDeclaration getByteDeclaration() {
        return (TypeDeclaration) getLanguageModuleDeclaration("Byte");
    }
    
    public Interface getComparableDeclaration() {
        return (Interface) getLanguageModuleDeclaration("Comparable");
    }
    
    public Interface getUsableDeclaration() {
        return (Interface) getLanguageModuleDeclaration("Usable");
    }
    
    public Interface getDestroyableDeclaration() {
        return (Interface) getLanguageModuleDeclaration("Destroyable");
    }
    
    public Interface getObtainableDeclaration() {
        return (Interface) getLanguageModuleDeclaration("Obtainable");
    }
    
    public Interface getOrdinalDeclaration() {
        return (Interface) getLanguageModuleDeclaration("Ordinal");
    }
        
    public Interface getEnumerableDeclaration() {
        return (Interface) getLanguageModuleDeclaration("Enumerable");
    }
        
    public Class getRangeDeclaration() {
        return (Class) getLanguageModuleDeclaration("Range");
    }
    
    public Class getSpanDeclaration() {
        return (Class) getLanguageModuleDeclaration("Span");
    }
    
    public Class getMeasureDeclaration() {
        return (Class) getLanguageModuleDeclaration("Measure");
    }
    
    public Class getTupleDeclaration() {
        return (Class) getLanguageModuleDeclaration("Tuple");
    }
    
    public TypeDeclaration getArrayDeclaration() {
        return (Class) getLanguageModuleDeclaration("Array");
    }
    
    public Interface getRangedDeclaration() {
        return (Interface) getLanguageModuleDeclaration("Ranged");
    }
        
    public Class getEntryDeclaration() {
        return (Class) getLanguageModuleDeclaration("Entry");
    }
    
    Type getCallableType(Reference ref, Type rt) {
        Type result = rt;
        Declaration declaration = ref.getDeclaration();
        if (declaration instanceof Functional) {
            Functional fd = (Functional) declaration;
            List<ParameterList> pls = fd.getParameterLists();
            for (int i=pls.size()-1; i>=0; i--) {
                boolean hasSequenced = false;
                boolean atLeastOne = false;
                int firstDefaulted = -1;
                List<Parameter> ps = 
                        pls.get(i).getParameters();
                List<Type> args = 
                        new ArrayList<Type>
                            (ps.size());
                for (int j=0; j<ps.size(); j++) {
                    Parameter p = ps.get(j);
                    if (p.getModel()==null) {
                        args.add(getUnknownType());
                    }
                    else {
                        TypedReference np = 
                                ref.getTypedParameter(p);
                        Type npt = np.getType();
                        if (npt==null) {
                            args.add(getUnknownType());
                        }
                        else {
                            if (p.isDefaulted() && 
                                    firstDefaulted==-1) {
                                firstDefaulted = j;
                            }
                            if (np.getDeclaration() 
                                    instanceof Functional) {
                                args.add(getCallableType(np, npt));
                            }
                            else if (p.isSequenced()) {
                                args.add(getIteratedType(npt));
                                hasSequenced = true;
                                atLeastOne = p.isAtLeastOne();
                            }
                            else {
                                args.add(npt);
                            }
                        }
                    }
                }
                Type paramListType = 
                        getTupleType(args, 
                                hasSequenced, atLeastOne, 
                                firstDefaulted);
                result = appliedType(getCallableDeclaration(), 