package org.simantics.scl.compiler.types; import java.util.ArrayList; import java.util.Arrays; import org.simantics.scl.compiler.environment.Environment; import org.simantics.scl.compiler.internal.types.HashCodeUtils; import org.simantics.scl.compiler.internal.types.TypeHashCodeContext; import org.simantics.scl.compiler.internal.types.ast.TForAllAst; import org.simantics.scl.compiler.internal.types.ast.TypeAst; import org.simantics.scl.compiler.types.exceptions.KindUnificationException; import org.simantics.scl.compiler.types.kinds.Kind; import org.simantics.scl.compiler.types.kinds.Kinds; import org.simantics.scl.compiler.types.util.Polarity; import org.simantics.scl.compiler.types.util.TypeUnparsingContext; import gnu.trove.map.hash.THashMap; import gnu.trove.map.hash.TObjectIntHashMap; import gnu.trove.set.hash.THashSet; public class TForAll extends Type { public final TVar var; public Type type; TForAll(TVar var, Type type) { if(NULL_CHECKS) { if(var == null || type == null) throw new NullPointerException(); } this.var = var; this.type = type; } private TForAll create(Type type) { if(type == this.type) return this; else return new TForAll(var, type); } @Override public TForAll replace(TVar var, Type replacement) { if(var == this.var) { if(replacement instanceof TVar) { return new TForAll((TVar)replacement, type.replace(var, replacement)); } else throw new IllegalStateException("Tried to replace a variable that is not free in the type."); } else return create(type.replace(var, replacement)); } @Override public TypeAst toTypeAst(TypeUnparsingContext context) { ArrayList vars = new ArrayList(); vars.add(context.getName(var)); Type cur = Types.canonical(type); while(cur instanceof TForAll) { TForAll forAll = (TForAll)cur; vars.add(context.getName(forAll.var)); cur = Types.canonical(forAll.type); } return new TForAllAst( vars.toArray(new String[vars.size()]), cur.toTypeAst(context)); } @Override public void updateHashCode(TypeHashCodeContext context) { context.append(TypeHashCodeContext.FORALL); TObjectIntHashMap varHashCode = context.createVarHashCode(); varHashCode.put(var, varHashCode.size()); type.updateHashCode(context); varHashCode.remove(var); } @Override public void collectFreeVars(ArrayList vars) { type.collectFreeVars(vars); vars.remove(var); } @Override public void collectMetaVars(ArrayList vars) { type.collectMetaVars(vars); } @Override public void collectMetaVars(THashSet vars) { type.collectMetaVars(vars); } @Override public void collectEffectMetaVars(ArrayList vars) { type.collectEffectMetaVars(vars); } @Override public boolean contains(TMetaVar other) { return type.contains(other); } @Override public Type convertMetaVarsToVars() { Type newType = type.convertMetaVarsToVars(); if(newType == type) return this; else return new TForAll(var, type); } @Override public boolean isGround() { return false; // The method is usually not called for quantified types // so it is unclear what it should do here. } public Kind inferKind(Environment context) throws KindUnificationException { type.checkKind(context, Kinds.STAR); return Kinds.STAR; } @Override public boolean containsMetaVars() { return type.containsMetaVars(); } @Override public void toName(TypeUnparsingContext context, StringBuilder b) { type.toName(context, b); } @Override public int getClassId() { return FORALL_ID; } @Override public void addPolarity(Polarity polarity) { type.addPolarity(polarity); } @Override public Type head() { return this; } @Override public Type copySkeleton(THashMap metaVarMap) { // Should never get here return new TMetaVar(Kinds.STAR); } @Override public int hashCode(int hash) { int count=1; { Type t = Types.canonical(type); while(t instanceof TForAll) { t = Types.canonical( ((TForAll)t).type ); ++count; } } TVar[] boundVars = new TVar[count]; boundVars[0] = var; TForAll t = this; { for(int i=1;i