--- /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.TEffectAst;
+import org.simantics.scl.compiler.internal.types.ast.TFunctionAst;
+import org.simantics.scl.compiler.internal.types.ast.TPredAst;
+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;
+
+public class TFun extends Type {
+ public final Type domain;
+ public final Type effect;
+ public final Type range;
+
+ TFun(Type domain, Type effect, Type range) {
+ if(domain == null)
+ throw new NullPointerException();
+ if(effect == null)
+ throw new NullPointerException();
+ if(range == null)
+ throw new NullPointerException();
+ /*domain = Types.weakCanonical(domain);
+ range = Types.weakCanonical(range);
+ if(domain instanceof TUnion)
+ throw new RuntimeException();
+ if(range instanceof TUnion)
+ throw new RuntimeException();*/
+
+ this.domain = domain;
+ this.effect = effect;
+ this.range = range;
+ }
+
+ @Override
+ public Type replace(TVar var, Type replacement) {
+ Type newDomain = domain.replace(var, replacement);
+ Type newEffect = effect.replace(var, replacement);
+ Type newRange = range.replace(var, replacement);
+ if(newDomain == domain && newEffect == effect && newRange == range)
+ return this;
+ else
+ return new TFun(newDomain, newEffect, newRange);
+ }
+
+ @Override
+ public TypeAst toTypeAst(TypeUnparsingContext context) {
+ TypeAst domainAst = domain.toTypeAst(context);
+ TypeAst rangeAst = range.toTypeAst(context);
+ if(Types.canonical(effect) != Types.NO_EFFECTS)
+ rangeAst = new TEffectAst(effect.toTypeAst(context), rangeAst);
+ Type dom = Types.canonical(domain);
+ if(dom instanceof TPred)
+ return new TPredAst(domainAst, rangeAst);
+ else if(dom == Types.PUNIT) {
+ //if(rangeAst instanceof TEffectAst)
+ return rangeAst;
+ /*else
+ return new TEffectAst(Types.NO_EFFECTS, rangeAst);*/
+ }
+ else
+ return new TFunctionAst(domainAst, rangeAst);
+ }
+
+ @Override
+ public void toName(TypeUnparsingContext context, StringBuilder b) {
+ b.append("FUNC_");
+ domain.toName(context, b);
+ b.append('_');
+ effect.toName(context, b);
+ b.append('_');
+ range.toName(context, b);
+ }
+
+ @Override
+ public void updateHashCode(TypeHashCodeContext context) {
+ context.append(TypeHashCodeContext.FUN);
+ domain.updateHashCode(context);
+ effect.updateHashCode(context);
+ range.updateHashCode(context);
+ }
+
+ @Override
+ public void collectFreeVars(ArrayList<TVar> vars) {
+ domain.collectFreeVars(vars);
+ effect.collectFreeVars(vars);
+ range.collectFreeVars(vars);
+ }
+
+ @Override
+ public void collectMetaVars(ArrayList<TMetaVar> vars) {
+ domain.collectMetaVars(vars);
+ effect.collectMetaVars(vars);
+ range.collectMetaVars(vars);
+ }
+
+ @Override
+ public void collectMetaVars(THashSet<TMetaVar> vars) {
+ domain.collectMetaVars(vars);
+ effect.collectMetaVars(vars);
+ range.collectMetaVars(vars);
+ }
+
+ @Override
+ public void collectEffectMetaVars(ArrayList<TMetaVar> vars) {
+ domain.collectEffectMetaVars(vars);
+ effect.collectMetaVars(vars);
+ range.collectEffectMetaVars(vars);
+ }
+
+ @Override
+ public boolean isGround() {
+ return domain.isGround() && effect.isGround() && range.isGround();
+ }
+
+ @Override
+ public boolean containsMetaVars() {
+ return domain.containsMetaVars()
+ || effect.containsMetaVars()
+ || range.containsMetaVars();
+ }
+
+ @Override
+ public boolean contains(TMetaVar other) {
+ return domain.contains(other)
+ || effect.contains(other)
+ || range.contains(other);
+ }
+
+ @Override
+ public int getClassId() {
+ return FUN_ID;
+ }
+
+ @Override
+ public Kind inferKind(Environment context)
+ throws KindUnificationException {
+ domain.checkKind(context, Kinds.STAR);
+ range.checkKind(context, Kinds.STAR);
+ return Kinds.STAR;
+ }
+
+ @Override
+ public Type convertMetaVarsToVars() {
+ Type newDomain = domain.convertMetaVarsToVars();
+ Type newEffect = effect.convertMetaVarsToVars();
+ Type newRange = range.convertMetaVarsToVars();
+ if(newDomain == domain && newEffect == effect && newRange == range)
+ return this;
+ else
+ return new TFun(newDomain, newEffect, newRange);
+ }
+
+ @Override
+ public boolean isMinimal() {
+ return Types.canonical(effect) == Types.NO_EFFECTS &&
+ range.isMinimal() && domain.isMaximal();
+ }
+
+ public boolean isMaximal() {
+ return false;
+ }
+
+ @Override
+ public void addPolarity(Polarity polarity) {
+ domain.addPolarity(polarity.flip());
+ effect.addPolarity(polarity);
+ range.addPolarity(polarity);
+ }
+
+ @Override
+ public Type head() {
+ return Types.ARROW;
+ }
+
+ @Override
+ public Type copySkeleton(THashMap<TMetaVar, TMetaVar> metaVarMap) {
+ Type newDomain = domain.copySkeleton(metaVarMap);
+ Type newEffect = Types.NO_EFFECTS;
+ Type newRange = range.copySkeleton(metaVarMap);
+ return new TFun(newDomain, newEffect, newRange);
+ }
+}