package org.simantics.scl.compiler.elaboration.expressions;
import java.util.ArrayList;
+import java.util.Arrays;
import org.simantics.scl.compiler.common.names.Name;
import org.simantics.scl.compiler.common.names.Names;
import org.simantics.scl.compiler.types.Type;
import org.simantics.scl.compiler.types.Types;
import org.simantics.scl.compiler.types.exceptions.MatchException;
-import org.simantics.scl.compiler.types.exceptions.UnificationException;
import org.simantics.scl.compiler.types.kinds.Kinds;
import org.simantics.scl.compiler.types.util.MultiFunction;
return new IApply(function.toIExpression(target), parametersI);
}
- private void inferType(TypingContext context, boolean ignoreResult) {
+ private Expression inferType(TypingContext context, boolean ignoreResult) {
function = function.inferType(context);
function = context.instantiate(function);
- MultiFunction mfun;
- try {
- mfun = Types.unifyFunction(function.getType(), parameters.length);
- } catch (UnificationException e) {
- int arity = Types.getArity(function.getType());
+ Type functionType = function.getType();
+
+ int arity = Types.getMaxArity(functionType);
+ if(arity < parameters.length) {
if(arity == 0)
context.getErrorLog().log(location, "Application of non-function.");
else
setType(Types.metaVar(Kinds.STAR));
for(int i=0;i<parameters.length;++i)
parameters[i] = parameters[i].inferType(context);
- return;
- }
- if((ignoreResult && Skeletons.canonicalSkeleton(mfun.returnType) instanceof TFun &&
- Types.canonical(mfun.effect) == Types.NO_EFFECTS) ||
- (context.isInPattern() && Skeletons.canonicalSkeleton(mfun.returnType) instanceof TFun)) {
- context.getErrorLog().log(location, "The function is applied with too few parameters.");
+ return this;
}
- // Check parameter types
- for(int i=0;i<parameters.length;++i)
- parameters[i] = parameters[i].checkType(context, mfun.parameterTypes[i]);
+ EApply current = this;
+ while(true) {
+ MultiFunction mfun = Types.unifyFunction2(functionType, current.parameters.length);
+ int marity = mfun.parameterTypes.length;
+ for(int i=0;i<marity;++i)
+ current.parameters[i] = current.parameters[i].checkType(context, mfun.parameterTypes[i]);
+ current.effect = mfun.effect;
+ context.declareEffect(location, mfun.effect);
+ current.setType(mfun.returnType);
- effect = mfun.effect;
-
- context.declareEffect(location, mfun.effect);
- setType(mfun.returnType);
+ if(marity < current.parameters.length) {
+ Expression[] missingParameters = Arrays.copyOfRange(current.parameters, marity, current.parameters.length);
+ functionType = mfun.returnType;
+ current.parameters = Arrays.copyOf(current.parameters, marity);
+ current = new EApply(current, missingParameters);
+ }
+ else {
+ if((ignoreResult && mfun.effect == Types.NO_EFFECTS && Skeletons.canonicalSkeleton(mfun.returnType) instanceof TFun) ||
+ (context.isInPattern() && Skeletons.canonicalSkeleton(mfun.returnType) instanceof TFun)) {
+ context.getErrorLog().log(location, "The function is applied with too few parameters.");
+ }
+ return current;
+ }
+ }
}
@Override
public Expression inferType(TypingContext context) {
if(parameters.length == 2 && function instanceof EConstant && ((EConstant)function).value.getName() == Names.Prelude_dollar)
return new EApply(location, parameters[0], parameters[1]).inferType(context);
- inferType(context, false);
- return this;
+ return inferType(context, false);
}
@Override
public Expression checkIgnoredType(TypingContext context) {
if(parameters.length == 2 && function instanceof EConstant && ((EConstant)function).value.getName() == Names.Prelude_dollar)
return new EApply(location, parameters[0], parameters[1]).checkIgnoredType(context);
- inferType(context, true);
+ Expression expression = inferType(context, true);
if(Types.canonical(getType()) != Types.UNIT)
- return new ESimpleLet(location, null, this, new ELiteral(NoRepConstant.PUNIT));
- return this;
+ expression = new ESimpleLet(location, null, expression, new ELiteral(NoRepConstant.PUNIT));
+ return expression;
}
public Type getLocalEffect() {
import java.util.Collections;
import java.util.List;
+import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;
import org.simantics.scl.compiler.errors.Locations;
import org.simantics.scl.compiler.internal.parsing.exceptions.SCLSyntaxErrorException;
import org.simantics.scl.compiler.internal.parsing.parser.SCLParserImpl;
effect,
type);
}
+
+ /**
+ * This function always success, but may return a multi function
+ * with arity smaller than given parameter
+ */
+ public static MultiFunction unifyFunction2(Type type, int arity) {
+ type = canonical(type);
+ Type[] parameterTypes = new Type[arity];
+ Type effect = Types.NO_EFFECTS;
+ int i;
+ for(i=0;i<arity;++i) {
+ if(type instanceof TFun) {
+ TFun fun = (TFun)type;
+ parameterTypes[i] = fun.getCanonicalDomain();
+ type = fun.getCanonicalRange();
+ effect = fun.getCanonicalEffect();
+ if(effect != Types.NO_EFFECTS) {
+ ++i;
+ break;
+ }
+ }
+ else if(type instanceof TMetaVar) {
+ Type domain = metaVar(Kinds.STAR);
+ parameterTypes[i] = domain;
+ Type range = metaVar(Kinds.STAR);
+ effect = metaVar(Kinds.EFFECT);
+ try {
+ ((TMetaVar) type).setRef(functionE(domain, effect, range));
+ } catch (UnificationException e) {
+ // Should never happen, if we have checked maximum arity before calling this function
+ throw new InternalCompilerError(e);
+ }
+ type = range;
+ ++i;
+ break;
+ }
+ else
+ break;
+ }
+
+ if(i < arity)
+ parameterTypes = Arrays.copyOf(parameterTypes, i);
+ return new MultiFunction(parameterTypes, effect, type);
+ }
+
public static MultiFunction unifyFunction(Type type, int arity) throws UnificationException {
Type[] parameterTypes = new Type[arity];
for(int i=0;i<arity;++i)
}
return arity;
}
+
+ public static int getMaxArity(Type type) {
+ type = Skeletons.canonicalSkeleton(type);
+ int arity = 0;
+ while(true) {
+ if(type instanceof TFun) {
+ ++arity;
+ type = Skeletons.canonicalSkeleton(((TFun) type).getCanonicalRange());
+ }
+ else if(type instanceof TMetaVar) {
+ return Integer.MAX_VALUE;
+ }
+ else
+ break;
+ }
+ return arity;
+ }
public static TMetaVar metaVar(Kind kind) {
return new TMetaVar(kind);