--- /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 java.util.List;
+
+import org.simantics.scl.compiler.environment.Environment;
+import org.simantics.scl.compiler.internal.types.TypeHashCodeContext;
+import org.simantics.scl.compiler.internal.types.ast.TApplyAst;
+import org.simantics.scl.compiler.internal.types.ast.TListAst;
+import org.simantics.scl.compiler.internal.types.ast.TTupleAst;
+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.TMultiApply;
+import org.simantics.scl.compiler.types.util.TypeUnparsingContext;
+
+
+
+/**
+ * Type application.
+ * @author Hannu Niemistö
+ */
+public class TApply extends Type {
+ public final Type function;
+ public final Type parameter;
+
+ public TApply(Type function, Type parameter) {
+ if(NULL_CHECKS) {
+ if(function == null)
+ throw new NullPointerException();
+ if(parameter == null)
+ throw new NullPointerException();
+ }
+ this.function = function;
+ this.parameter = parameter;
+ }
+
+ private TApply create(Type function, Type parameter) {
+ if(function == this.function && parameter == this.parameter)
+ return this;
+ else
+ return new TApply(function, parameter);
+ }
+
+ @Override
+ public TApply replace(TVar var, Type replacement) {
+ return create(
+ function.replace(var, replacement),
+ parameter.replace(var, replacement));
+ }
+
+ @Override
+ public TypeAst toTypeAst(TypeUnparsingContext context) {
+ TMultiApply multiApply = Types.toMultiApply(this);
+
+ Type function = multiApply.function;
+ List<Type> parameters = multiApply.parameters;
+
+ TypeAst ast = null;
+ int parameterPos = 0;
+
+ if(function instanceof TCon) {
+ /*if(function == Types.ARROW && parameters.size() >= 2) {
+ ast = new TFunctionAst(
+ parameters.get(0).toTypeAst(context),
+ parameters.get(1).toTypeAst(context));
+ parameterPos = 2;
+ }
+ else*/ if(function == Types.LIST && parameters.size() >= 1) {
+ ast = new TListAst(
+ parameters.get(0).toTypeAst(context));
+ parameterPos = 1;
+ }
+ else {
+ TCon con = (TCon)function;
+ if(con.module == Types.BUILTIN && con.name.charAt(0)=='(') {
+ int tupleLength = con.name.length()-2;
+ if(tupleLength>0) ++tupleLength;
+ if(parameters.size() >= tupleLength) {
+ TypeAst[] components = new TypeAst[tupleLength];
+ for(int i=0;i<tupleLength;++i)
+ components[i] = parameters.get(i).toTypeAst(context);
+ ast = new TTupleAst(components);
+ parameterPos = tupleLength;
+ }
+ }
+ }
+ }
+ if(ast == null)
+ ast = function.toTypeAst(context);
+ for(;parameterPos < multiApply.parameters.size();++parameterPos)
+ ast = new TApplyAst(
+ ast,
+ parameters.get(parameterPos).toTypeAst(context));
+ return ast;
+ }
+
+ @Override
+ public void updateHashCode(TypeHashCodeContext context) {
+ context.append(TypeHashCodeContext.APPLY);
+ function.updateHashCode(context);
+ parameter.updateHashCode(context);
+ }
+
+ @Override
+ public void collectFreeVars(ArrayList<TVar> vars) {
+ function.collectFreeVars(vars);
+ parameter.collectFreeVars(vars);
+ }
+
+ @Override
+ public void collectMetaVars(ArrayList<TMetaVar> vars) {
+ function.collectMetaVars(vars);
+ parameter.collectMetaVars(vars);
+ }
+
+ @Override
+ public void collectMetaVars(THashSet<TMetaVar> vars) {
+ function.collectMetaVars(vars);
+ parameter.collectMetaVars(vars);
+ }
+
+ @Override
+ public void collectEffectMetaVars(ArrayList<TMetaVar> vars) {
+ function.collectEffectMetaVars(vars);
+ parameter.collectEffectMetaVars(vars);
+ }
+
+ @Override
+ public boolean contains(TMetaVar other) {
+ return function.contains(other) || parameter.contains(other);
+ }
+
+ @Override
+ public Type convertMetaVarsToVars() {
+ Type newFunction = function.convertMetaVarsToVars();
+ Type newParameter = parameter.convertMetaVarsToVars();
+ if(newFunction == function && newParameter == parameter)
+ return this;
+ else
+ return new TApply(newFunction, newParameter);
+ }
+
+ @Override
+ public boolean isGround() {
+ return function.isGround() && parameter.isGround();
+ }
+
+ public void checkKind(Environment context, Kind requiredKind) throws KindUnificationException {
+ Kind functionKind = function.inferKind(context);
+ Kind parameterKind = parameter.inferKind(context);
+ Kinds.unify(functionKind, Kinds.arrow(parameterKind, requiredKind));
+ }
+
+ @Override
+ public boolean containsMetaVars() {
+ return function.containsMetaVars() || parameter.containsMetaVars();
+ }
+
+ @Override
+ public void toName(TypeUnparsingContext context, StringBuilder b) {
+ function.toName(context, b);
+ b.append('_');
+ parameter.toName(context, b);
+ }
+
+ @Override
+ public int getClassId() {
+ return APPLY_ID;
+ }
+
+ @Override
+ public void addPolarity(Polarity polarity) {
+ function.addPolarity(Polarity.BIPOLAR);
+ parameter.addPolarity(Polarity.BIPOLAR);
+ }
+
+ @Override
+ public Type head() {
+ return function.head();
+ }
+
+ @Override
+ public Type copySkeleton(THashMap<TMetaVar, TMetaVar> metaVarMap) {
+ Type newFunction = function.copySkeleton(metaVarMap);
+ Type newParameter = parameter.copySkeleton(metaVarMap);
+ if(newFunction == function && newParameter == parameter)
+ return this;
+ else
+ return new TApply(newFunction, newParameter);
+ }
+}