--- /dev/null
+package org.simantics.scl.compiler.types;
+
+import gnu.trove.map.hash.THashMap;
+import gnu.trove.set.hash.THashSet;
+
+import java.util.ArrayList;
+
+import org.simantics.scl.compiler.environment.Environment;
+import org.simantics.scl.compiler.internal.types.TypeHashCodeContext;
+import org.simantics.scl.compiler.internal.types.ast.TVarAst;
+import org.simantics.scl.compiler.internal.types.ast.TypeAst;
+import org.simantics.scl.compiler.types.exceptions.KindUnificationException;
+import org.simantics.scl.compiler.types.exceptions.UnificationException;
+import org.simantics.scl.compiler.types.kinds.KMetaVar;
+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;
+
+
+
+/**
+ * A meta-variable, a type that is currently unknown. This class
+ * should occur only during type inference. Method removeMetaVars
+ * can be used to remove all instances of TMetaVar from the type.
+ *
+ * @author Hannu Niemistö
+ */
+public class TMetaVar extends Type {
+ public static final TMetaVar[] EMPTY_ARRAY = new TMetaVar[0];
+
+ Type ref = null;
+ Polarity polarity = Polarity.NO_POLARITY;
+ private Kind kind;
+
+ TMetaVar(Kind kind) {
+ this.kind = kind;
+ }
+
+ TMetaVar(Kind kind, Polarity polarity) {
+ this.kind = kind;
+ this.polarity = polarity;
+ }
+
+ public Kind getKind() {
+ if(kind instanceof KMetaVar)
+ kind = Kinds.canonical(kind);
+ return kind;
+ }
+
+ @Override
+ public Type replace(TVar var, Type replacement) {
+ if(ref == null)
+ return this;
+ else {
+ Type newRef = ref.replace(var, replacement);
+ if(newRef != ref)
+ return newRef;
+ else
+ // We could also return newRef here, but in this way
+ // we don't have to copy so many parent types.
+ return this;
+ }
+ }
+
+ @Override
+ public TypeAst toTypeAst(TypeUnparsingContext context) {
+ if(ref == null)
+ return new TVarAst(/*polarity.getSymbol() +*/ context.getName(this));
+ else
+ return ref.toTypeAst(context);
+ }
+
+ @Override
+ public int hashCode() {
+ if(ref == null)
+ return System.identityHashCode(this);
+ else
+ return ref.hashCode();
+ }
+
+ @Override
+ public void updateHashCode(TypeHashCodeContext context) {
+ if(ref == null)
+ context.append(System.identityHashCode(this));
+ else
+ ref.updateHashCode(context);
+ }
+
+ @Override
+ public void collectFreeVars(ArrayList<TVar> vars) {
+ if(ref != null)
+ ref.collectFreeVars(vars);
+ }
+
+ @Override
+ public void collectMetaVars(ArrayList<TMetaVar> vars) {
+ if(ref == null)
+ vars.add(this);
+ else
+ ref.collectMetaVars(vars);
+ }
+
+ @Override
+ public void collectMetaVars(THashSet<TMetaVar> vars) {
+ if(ref == null)
+ vars.add(this);
+ else
+ ref.collectMetaVars(vars);
+ }
+
+ @Override
+ public void collectEffectMetaVars(ArrayList<TMetaVar> vars) {
+ if(ref != null)
+ ref.collectEffectMetaVars(vars);
+ }
+
+ public void setRef(Type a) throws UnificationException {
+ a = Types.weakCanonical(a);
+ if(a.contains(this))
+ throw new UnificationException(this, a);
+ ref = a;
+ if(polarity != Polarity.NO_POLARITY)
+ a.addPolarity(polarity);
+ }
+
+ public Type getRef() {
+ return ref;
+ }
+
+ @Override
+ public boolean contains(TMetaVar other) {
+ if(ref == null)
+ return this == other;
+ else
+ return ref.contains(other);
+ }
+
+ @Override
+ public Type convertMetaVarsToVars() {
+ if(ref == null) {
+ if(kind == Kinds.EFFECT && !polarity.isNegative())
+ ref = Types.NO_EFFECTS;
+ else
+ ref = Types.var(getKind());
+ return ref;
+ }
+ else
+ return ref.convertMetaVarsToVars();
+ }
+
+ @Override
+ public boolean isGround() {
+ if(ref == null)
+ return false;
+ else
+ return ref.isGround();
+ }
+
+ public Kind inferKind(Environment context) throws KindUnificationException {
+ return Kinds.metaVar();
+ }
+
+ @Override
+ public boolean containsMetaVars() {
+ if(ref == null)
+ return true;
+ else
+ return ref.containsMetaVars();
+ }
+
+ @Override
+ public void toName(TypeUnparsingContext context, StringBuilder b) {
+ if(ref != null)
+ ref.toName(context, b);
+ else
+ b.append(context.getName(this));
+ }
+
+ @Override
+ public int getClassId() {
+ return METAVAR_ID;
+ }
+
+ @Override
+ public boolean isMaximal() {
+ return ref != null && ref.isMaximal();
+ }
+
+ @Override
+ public boolean isMinimal() {
+ return ref != null && ref.isMinimal();
+ }
+
+ @Override
+ public void addPolarity(Polarity polarity) {
+ if(ref != null)
+ ref.addPolarity(polarity);
+ else
+ this.polarity = this.polarity.add(polarity);
+ }
+
+ public Polarity getPolarity() {
+ return polarity;
+ }
+
+ @Override
+ public void collectConcreteEffects(ArrayList<TCon> concreteEffects) {
+ if(ref != null)
+ ref.collectConcreteEffects(concreteEffects);
+ }
+
+ @Override
+ public Type head() {
+ if(ref != null)
+ return ref.head();
+ else
+ return this;
+ }
+
+ @Override
+ public Type copySkeleton(THashMap<TMetaVar, TMetaVar> metaVarMap) {
+ if(ref != null)
+ return ref.copySkeleton(metaVarMap);
+ else {
+ TMetaVar result = metaVarMap.get(this);
+ if(result == null) {
+ result = new TMetaVar(kind, polarity);
+ metaVarMap.put(this, result);
+ }
+ return result;
+ }
+ }
+}