Removed equations context from org.simantics.scl.runtime
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / types / Types.java
1 package org.simantics.scl.compiler.types;
2
3 import java.io.StringReader;
4 import java.util.ArrayList;
5 import java.util.Arrays;
6 import java.util.Collections;
7 import java.util.List;
8
9 import org.simantics.scl.compiler.errors.Locations;
10 import org.simantics.scl.compiler.internal.parsing.exceptions.SCLSyntaxErrorException;
11 import org.simantics.scl.compiler.internal.parsing.parser.SCLParserImpl;
12 import org.simantics.scl.compiler.internal.types.HashConsing;
13 import org.simantics.scl.compiler.internal.types.TypeElaborationContext;
14 import org.simantics.scl.compiler.internal.types.effects.EffectIdMap;
15 import org.simantics.scl.compiler.types.exceptions.KindUnificationException;
16 import org.simantics.scl.compiler.types.exceptions.MatchException;
17 import org.simantics.scl.compiler.types.exceptions.Problem;
18 import org.simantics.scl.compiler.types.exceptions.SCLTypeParseException;
19 import org.simantics.scl.compiler.types.exceptions.UnificationException;
20 import org.simantics.scl.compiler.types.kinds.Kind;
21 import org.simantics.scl.compiler.types.kinds.Kinds;
22 import org.simantics.scl.compiler.types.util.ITypeEnvironment;
23 import org.simantics.scl.compiler.types.util.MultiApply;
24 import org.simantics.scl.compiler.types.util.MultiFunction;
25 import org.simantics.scl.compiler.types.util.TMultiApply;
26 import org.simantics.scl.compiler.types.util.TypeUnparsingContext;
27 import org.simantics.scl.compiler.types.util.Typed;
28
29 import gnu.trove.map.hash.THashMap;
30 import gnu.trove.set.hash.THashSet;
31
32 /**
33  * An utility class for creating and manipulating types.
34  * 
35  * @author Hannu Niemistö
36  */
37 public class Types {
38
39     private static final HashConsing<TCon> conCache = 
40             new HashConsing<TCon>() {
41         protected boolean equals(TCon a, TCon b) {
42             return a.name.equals(b.name) && a.module.equals(b.module);
43         }
44
45         protected int hashCode(TCon obj) {
46             return obj.module.hashCode()*31 + obj.name.hashCode();
47         }
48     };
49
50     public static final String BUILTIN = "Builtin";
51
52     public static final TCon BOOLEAN = con(BUILTIN, "Boolean");
53     public static final TCon BYTE = con(BUILTIN, "Byte");
54     public static final TCon CHARACTER = con(BUILTIN, "Character");
55     public static final TCon SHORT = con(BUILTIN, "Short");
56     public static final TCon INTEGER = con(BUILTIN, "Integer");
57     public static final TCon LONG = con(BUILTIN, "Long");
58     public static final TCon FLOAT = con(BUILTIN, "Float");
59     public static final TCon DOUBLE = con(BUILTIN, "Double");
60     
61     public static final TCon BOOLEAN_ARRAY = con(BUILTIN, "BooleanArray");
62     public static final TCon BYTE_ARRAY = con(BUILTIN, "ByteArray");
63     public static final TCon CHARACTER_ARRAY = con(BUILTIN, "CharacterArray");
64     public static final TCon SHORT_ARRAY = con(BUILTIN, "ShortArray");
65     public static final TCon INTEGER_ARRAY = con(BUILTIN, "IntegerArray");
66     public static final TCon LONG_ARRAY = con(BUILTIN, "LongArray");
67     public static final TCon FLOAT_ARRAY = con(BUILTIN, "FloatArray");
68     public static final TCon DOUBLE_ARRAY = con(BUILTIN, "DoubleArray");
69
70     public static final TCon STRING = con(BUILTIN, "String");
71     public static final TCon ARROW = con(BUILTIN, "->");
72
73     public static final TCon LIST = con(BUILTIN, "[]");
74     public static final TCon VECTOR = con(BUILTIN, "Vector");
75     public static final TCon MVECTOR = con(BUILTIN, "MVector");
76     public static final TCon MAYBE = con(BUILTIN, "Maybe");
77     public static final TCon ARRAY = con(BUILTIN, "Array");
78     public static final TCon UNIT = con(BUILTIN, "()");
79     
80     public static final TCon PUNIT = con(BUILTIN, "@");
81     
82     public static final TCon TYPE_PROXY = con(BUILTIN, "TypeProxy");
83
84     public static final TCon TYPEABLE = con(BUILTIN, "Typeable");
85     public static final TCon SERIALIZABLE = con(BUILTIN, "Serializable");
86     public static final TCon VEC_COMP = con(BUILTIN, "VecComp");
87     public static final TCon BINDING = con(BUILTIN, "Binding");
88
89     public static final TCon TYPE = con(BUILTIN, "Type");
90     
91     public static final TCon DYNAMIC = con("Prelude", "Dynamic");
92     public static final TCon VARIANT = con(BUILTIN, "Variant");
93     
94     public static final TCon ADDITIVE = con("Prelude", "Additive");
95     public static final TCon MONAD = con("Prelude", "Monad");
96     public static final TCon INTEGRAL = con("Prelude", "Integral");
97     public static final TCon RING = con("Prelude", "Ring");
98     public static final TCon ORDERED_RING = con("Prelude", "OrderedRing");
99     public static final TCon REAL = con("Prelude", "Real");
100     public static final TCon SHOW = con("Prelude", "Show");
101     public static final TCon EQ = con("Prelude", "Eq");
102     public static final TCon ORD = con("Prelude", "Ord");
103     public static final TCon HASHABLE = con("Prelude", "Hashable");
104     public static final TCon IO = con("Serialization", "IO");
105
106     public static final Type REF = con("Prelude", "Ref");
107     
108     public static final TCon RANDOM = Types.con("Random", "Random");
109     public static final TCon READ_GRAPH = Types.con("Simantics/DB", "ReadGraph");
110     public static final TCon WRITE_GRAPH = Types.con("Simantics/DB", "WriteGraph");
111     public static final Type RESOURCE = Types.con("Simantics/DB", "Resource"); 
112     
113     public static final TUnion NO_EFFECTS = new TUnion();
114     public static final TCon PROC = con(BUILTIN, "Proc");
115     
116     public static final TCon BRANCH_POINT = con(BUILTIN, "BranchPoint");
117
118     private volatile static TCon[] tupleCache = new TCon[] {
119         UNIT, null
120     };
121
122     private static final ITypeEnvironment DUMMY_TYPE_ENVIRONMENT = new ITypeEnvironment() {
123
124         @Override
125         public TCon resolve(String namespace, String name) {
126             if(namespace == null)
127                 return con(BUILTIN, name);
128             else
129                 return con(namespace, name);
130         }
131
132     };
133     
134     public static boolean isPrimitive(Type type) {
135         return type == BOOLEAN || type == BYTE || type == CHARACTER || type == SHORT ||
136                         type == INTEGER || type == LONG || type == FLOAT || type == DOUBLE || type == STRING;
137     }
138     
139     public static boolean isNumeric(Type type) {
140         return type == BYTE || type == SHORT || type == INTEGER || type == LONG || type == FLOAT || type == DOUBLE;
141     }
142         
143     public static TApply apply(Type function, Type parameter) {
144         return new TApply(function, parameter);
145     }
146
147     public static Type apply(Type function, Type ... parameters) {
148         for(Type parameter : parameters)
149             function = apply(function, parameter);
150         return function;
151     }
152     
153     /**
154      * Get the concrete type pointed to by a chain of type meta-variables.
155      */
156     public static Type canonical(Type type) {
157         while(type instanceof TMetaVar) {
158             TMetaVar metaVar = (TMetaVar)type;
159             type = metaVar.ref;
160             if(type == null)
161                 return metaVar;
162         }
163         return type;
164     }
165
166     public static Type closure(Type type, ArrayList<TVar> vars) {
167         for(int i=vars.size()-1;i>=0;--i)
168             type = forAll(vars.get(i), type);
169         return type;
170     }
171
172     public static Type closure(Type type, TVar[] vars) {
173         for(int i=vars.length-1;i>=0;--i)
174             type = forAll(vars[i], type);
175         return type;
176     }
177
178     public static Type closure(Type type) {
179         return closure(type, freeVars(type));
180     }
181
182     public static TCon con(String module, String name) {
183         return conCache.canonical(new TCon(module, name));
184     }
185
186     public static Type[] concat(Type[] a, Type[] b) {
187         if(a.length == 0)
188             return b;
189         if(b.length == 0)
190             return a;
191         Type[] result = new Type[a.length + b.length];
192         for(int i=0;i<a.length;++i)
193             result[i] = a[i];
194         for(int i=0;i<b.length;++i)
195             result[i+a.length] = b[i];
196         return result;
197     }
198
199     public static TVar[] concat(TVar[] a, TVar[] b) {
200         if(a.length == 0)
201             return b;
202         if(b.length == 0)
203             return a;
204         TVar[] result = new TVar[a.length + b.length];
205         for(int i=0;i<a.length;++i)
206             result[i] = a[i];
207         for(int i=0;i<b.length;++i)
208             result[i+a.length] = b[i];
209         return result;
210     }
211
212     public static boolean equals(TApply a, TApply b) {
213         return equals(a.parameter, b.parameter)
214                 && equals(a.function , b.function );
215     }
216
217     public static boolean equals(TFun a, TFun b) {
218         return equals(a.domain, b.domain)
219                 && equals(a.effect, b.effect)
220                 && equals(a.range, b.range);
221     }
222     
223     public static boolean subsumes(TFun a, TFun b) {
224         return subsumes(b.domain, a.domain)
225                 && subsumesEffect(a.effect, b.effect)
226                 && subsumes(a.range, b.range);
227     }
228
229     public static boolean subsumesEffect(Type a, Type b) {
230         EffectIdMap idMap = new EffectIdMap();
231         ArrayList<TMetaVar> mVars = new ArrayList<TMetaVar>(0);
232         int idA = idMap.toId(a, mVars);
233         int idB = idMap.toId(b, mVars);
234         return (idA&idB) == idA;
235     }
236     
237     public static boolean equalsEffect(Type a, Type b) {
238         EffectIdMap idMap = new EffectIdMap();
239         ArrayList<TMetaVar> mVars = new ArrayList<TMetaVar>(0);
240         int idA = idMap.toId(a, mVars);
241         int idB = idMap.toId(b, mVars);
242         return idA == idB;
243     }
244
245     public static boolean equals(TForAll a, TForAll b) {
246         Kind aKind = a.var.getKind();
247         if(!Kinds.equalsCanonical(aKind, b.var.getKind()))
248             return false;
249         TVar newVar = var(aKind);
250         return equals(a.type.replace(a.var, newVar), b.type.replace(b.var, newVar));
251     }
252
253     public static boolean equals(TPred a, TPred b) {
254         if(a.typeClass != b.typeClass 
255                 || a.parameters.length != b.parameters.length)
256             return false;
257         Type[] aParameters = a.parameters;
258         Type[] bParameters = b.parameters;
259         for(int i=0;i<aParameters.length;++i)
260             if(!equals(aParameters[i], bParameters[i]))
261                 return false;
262         return true;
263     }
264
265     public static boolean equals(TUnion a, TUnion b) {
266         if(a.effects.length != b.effects.length)
267             return false;
268         for(int i=0;i<a.effects.length;++i)
269             if(!equals(a.effects[i], b.effects[i]))
270                 return false;
271         return true;
272     }
273
274     /**
275      * Tests equality of two types. Unbound TVars
276      * are equal only if they are the same variable.
277      * Bound TMetaVar is equal to the type it is bound to.
278      * Unbound TMetaVars are equal only if they are the same metavariable.
279      * Order of predicates and forall quantifiers matters.
280      */
281     public static boolean equals(Type a, Type b) {
282         a = canonical(a);
283         b = canonical(b);
284         if(a == b)
285             return true;
286         Class<?> ca = a.getClass();
287         Class<?> cb = b.getClass();
288         if(ca != cb)
289             return false;
290         if(ca == TApply.class) 
291             return equals((TApply)a, (TApply)b);
292         else if(ca == TFun.class) 
293             return equals((TFun)a, (TFun)b);
294         else if(ca == TForAll.class)
295             return equals((TForAll)a, (TForAll)b);
296         else if(ca == TPred.class) 
297             return equals((TPred)a, (TPred)b);
298         else if(ca == TUnion.class) 
299             return equals((TUnion)a, (TUnion)b);        
300         else // ca == TCon.class 
301             // || (ca == TMetaVar.class && a.ref == null && b.ref == null) 
302             // || ca = TVar.class 
303             return false; // Equals only if a == b, that was already tested
304     }
305     
306     public static boolean subsumes(Type a, Type b) {
307         a = canonical(a);
308         b = canonical(b);
309         if(a == b)
310             return true;
311         Class<?> ca = a.getClass();
312         Class<?> cb = b.getClass();
313         if(ca != cb)
314             return false;
315         if(ca == TApply.class) 
316             return equals((TApply)a, (TApply)b);
317         else if(ca == TFun.class) 
318             return subsumes((TFun)a, (TFun)b);
319         else if(ca == TForAll.class) {
320             TForAll aForAll = (TForAll)a;
321             TForAll bForAll = (TForAll)b;
322             TVar newVar = var(aForAll.var.getKind());
323             return subsumes(aForAll.type.replace(aForAll.var, newVar),
324                             bForAll.type.replace(bForAll.var, newVar));
325         }
326         else if(ca == TPred.class) 
327             return equals((TPred)a, (TPred)b);
328         else if(ca == TUnion.class) 
329             return equals((TUnion)a, (TUnion)b);        
330         else // ca == TCon.class 
331             // || (ca == TMetaVar.class && a.ref == null && b.ref == null) 
332             // || ca = TVar.class 
333             return false; // Equals only if a == b, that was already tested
334     }
335
336     public static TForAll forAll(TVar parameter, Type type) {
337         return new TForAll(parameter, type);
338     }
339
340     public static Type forAll(TVar[] parameters, Type type) {
341         for(int i=parameters.length-1;i>=0;--i)
342             type = forAll(parameters[i], type);
343         return type;
344     }
345
346     public static ArrayList<TVar> freeVars(Type type) {
347         ArrayList<TVar> vars = new ArrayList<TVar>(2);
348         type.collectFreeVars(vars);
349         return vars;
350     }
351
352     public static ArrayList<TVar> freeVars(Type[] types) {
353         ArrayList<TVar> vars = new ArrayList<TVar>(2);
354         for(Type type : types)
355             type.collectFreeVars(vars);
356         return vars;
357     }
358
359     public static TVar[] freeVarsArray(Type type) {
360         ArrayList<TVar> vars = freeVars(type);        
361         return vars.toArray(new TVar[vars.size()]);
362     }
363
364     public static TVar[] freeVarsArray(Type[] types) {
365         ArrayList<TVar> vars = freeVars(types);        
366         return vars.toArray(new TVar[vars.size()]);
367     }
368
369     public static TPred pred(TCon typeClass, Type ... parameters) {
370         return new TPred(typeClass, parameters);
371     }
372
373     public static Type function(Type ... types) {
374         Type result = types[types.length-1];
375         for(int i=types.length-2;i>=0;--i)
376             result = function(types[i], result);
377         return result;
378     }
379
380     public static Type function(Type from, Type to) {
381         return new TFun(from, Types.NO_EFFECTS, to);
382     }
383
384     public static Type function(Type[] from, Type to) {
385         for(int i=from.length-1;i>=0;--i)
386             to = function(from[i], to);
387         return to;
388     }
389
390     public static TFun functionE(Type from, Type effect, Type to) {
391         return new TFun(from, effect, to);
392     }
393
394     public static Type functionE(Type[] from, Type effect, Type to) {
395         for(int i=from.length-1;i>=0;--i) {
396             to = functionE(from[i], effect, to);
397             effect = Types.NO_EFFECTS;
398         }
399         return to;
400     }
401
402     public static Type removeForAll(Type type, ArrayList<TVar> vars) {
403         while(true) {
404             if(type instanceof TForAll) {
405                 TForAll forAll = (TForAll)type;
406                 type = forAll.type;
407                 vars.add(forAll.var);
408             }
409             else if(type instanceof TMetaVar) {
410                 TMetaVar var = (TMetaVar)type;
411                 if(var.ref != null)
412                     type = var.ref;
413                 else
414                     return type;
415             }
416             else
417                 return type;
418         }
419     }
420     
421     public static Type removeForAll(Type type) {
422         while(true) {
423             if(type instanceof TForAll) {
424                 TForAll forAll = (TForAll)type;
425                 type = forAll.type;
426             }
427             else if(type instanceof TMetaVar) {
428                 TMetaVar var = (TMetaVar)type;
429                 if(var.ref != null)
430                     type = var.ref;
431                 else
432                     return type;
433             }
434             else
435                 return type;
436         }
437     }
438
439     public static Type instantiate(TForAll forAll, ArrayList<TMetaVar> vars) {
440         TMetaVar metaVar = metaVar(forAll.var.getKind());
441         vars.add(metaVar);
442         return instantiate(forAll.type.replace(forAll.var, metaVar), vars);
443     }
444
445     public static Type instantiate(Type type, ArrayList<TMetaVar> vars) {
446         if(type == null)
447             throw new NullPointerException();
448         type = canonical(type);
449         if(type instanceof TForAll)
450             return instantiate((TForAll)type, vars);
451         else
452             return type;
453     }
454
455     public static Type list(Type parameter) {
456         return apply(LIST, parameter);
457     }
458     
459     public static Type vector(Type parameter) {
460         return apply(VECTOR, parameter);
461     }
462     
463     public static Type mvector(Type parameter) {
464         return apply(MVECTOR, parameter);
465     }
466
467     public static MultiFunction matchFunction(Type type, int arity) throws MatchException {
468         if (type instanceof TForAll)
469                 return matchFunction(((TForAll)type).type, arity);
470         
471         type = canonical(type);
472         /*while(type instanceof TForAll)
473             type = canonical(((TForAll)type).type);*/
474         Type[] parameterTypes = new Type[arity];
475         Type effect = Types.NO_EFFECTS;
476         for(int i=0;i<arity;++i) {
477             if(type instanceof TFun) {
478                 TFun fun = (TFun)type;            
479                 parameterTypes[i] = fun.domain;
480                 type = canonical(fun.range);
481                 if(i == arity-1)
482                     effect = fun.effect;
483                 else if(Types.canonical(fun.effect) != Types.NO_EFFECTS)
484                     throw new MatchException();
485             }
486             /*else if(type instanceof TMetaVar) {
487                 TMetaVar metaVar = (TMetaVar)type;
488                 type = Types.metaVar(Kinds.STAR);
489                 Type template = type;
490                 effect = Types.metaVar(Kinds.EFFECT);
491                 for(int j=arity-1;j>=i;--j) {
492                     Type pType = Types.metaVar(Kinds.STAR);
493                     parameterTypes[j] = pType;
494                     template = Types.functionE(pType, 
495                             j==arity-1 ? effect : Types.NO_EFFECTS,
496                                     template);
497                 }
498                 try {
499                     metaVar.setRef(template);
500                 } catch (UnificationException e) {
501                     // Should never happen
502                     throw new MatchException();                    
503                 }
504                 break;
505             }*/
506             /*else if(type instanceof TApply) {
507                 TApply apply1 = (TApply)type;
508                 Type function1 = canonical(apply1.function);
509                 if(function1 instanceof TApply) {
510                     TApply apply2 = (TApply)function1;
511                     Type function2 = canonical(apply2.function);
512                     if(function2 == ARROW) {
513                         result[i] = apply2.parameter;
514                         type = canonical(apply1.parameter);
515                     }
516                     else
517                         throw new MatchException();
518                 }
519                 else
520                     throw new MatchException();
521             }*/
522             else
523                 throw new MatchException();
524         }
525         return new MultiFunction(parameterTypes, effect, type);
526     }
527
528     public static boolean isApply(Type func, int arity, Type type) {        
529         while(arity-- > 0) {
530             type = canonical(type);
531             if(!(type instanceof TApply))
532                 return false;
533             type = ((TApply)type).function;
534         }
535         return equals(func, type);
536     }
537
538     public static Type matchApply(TCon func, Type type) throws MatchException {
539         type = canonical(type);
540         if(type instanceof TApply) {
541             TApply apply = (TApply)type;
542             Type f = canonical(apply.function);
543             if(f.equals(func))
544                 return canonical(apply.parameter);
545         }
546         throw new MatchException();
547     }
548     
549     public static MultiApply matchApply(Type type) {
550         ArrayList<Type> parameters = new ArrayList<Type>();
551         type = canonical(type);
552         while(type instanceof TApply) {
553             TApply apply = (TApply)type;
554             parameters.add(Types.canonical(apply.parameter));
555             type = canonical(apply.function);
556         }
557         return new MultiApply(type, parameters.toArray(new Type[parameters.size()]));
558     }
559     
560     public static Type unifyApply(TCon func, Type type) throws MatchException {
561         type = canonical(type);
562         if(type instanceof TApply) {
563             TApply apply = (TApply)type;
564             Type f = canonical(apply.function);
565             if(f.equals(func))
566                 return canonical(apply.parameter);
567             else if(f instanceof TMetaVar)
568                 try {
569                     ((TMetaVar)f).setRef(func);
570                     return canonical(apply.parameter);
571                 } catch (UnificationException e) {
572                     throw new MatchException();
573                 }
574         }
575         else if(type instanceof TMetaVar) {
576             TMetaVar parameter = Types.metaVar(Kinds.metaVar());
577             try {
578                 ((TMetaVar) type).setRef(apply(func, parameter));
579             } catch (UnificationException e) {
580                 throw new MatchException();
581             }
582             return parameter;
583         }
584         throw new MatchException();
585     }
586
587     public static MultiFunction matchFunction(Type type) {
588         type = canonical(type);
589         while(type instanceof TForAll)
590             type = canonical(((TForAll)type).type);
591         ArrayList<Type> parameterTypes = new ArrayList<Type>();
592         Type effect = Types.NO_EFFECTS;
593         while(true) {
594             if(type instanceof TFun) {
595                 TFun fun = (TFun)type;
596                 parameterTypes.add(fun.domain);
597                 type = canonical(fun.range);
598                 if(canonical(fun.effect) != Types.NO_EFFECTS) {
599                     effect = fun.effect;
600                     break;
601                 }
602             }            
603             /*else if(type instanceof TApply) {
604                 TApply apply1 = (TApply)type;
605                 Type function1 = canonical(apply1.function);
606                 if(function1 instanceof TApply) {
607                     TApply apply2 = (TApply)function1;
608                     Type function2 = canonical(apply2.function);
609                     if(function2 == ARROW) {
610                         types.add(apply2.parameter);
611                         type = apply1.parameter;
612                     }
613                     else {
614                         types.add(type);
615                         break;
616                     }
617                 }
618                 else {
619                     types.add(type);
620                     break;
621                 }
622             }*/
623             else {
624                 break;
625             }
626         }
627         return new MultiFunction(
628                 parameterTypes.toArray(new Type[parameterTypes.size()]),
629                 effect,
630                 type);
631     }
632
633     public static MultiFunction unifyFunction(Type type, int arity) throws UnificationException {
634         Type[] parameterTypes = new Type[arity];
635         for(int i=0;i<arity;++i)
636             parameterTypes[i] = metaVar(Kinds.STAR);
637         Type effect = metaVar(Kinds.EFFECT);
638         Type requiredType = metaVar(Kinds.STAR);
639         MultiFunction result = new MultiFunction(parameterTypes, effect, requiredType);
640
641         for(int i=arity-1;i>=0;--i) {
642             requiredType = functionE(parameterTypes[i], effect, requiredType);
643             effect = Types.NO_EFFECTS;
644         }
645         unify(type, requiredType);
646         return result;
647     }
648
649     private static Type getRangeIfFunction(Type type) {
650         type = canonical(type);
651
652         if(type instanceof TFun) {
653             return ((TFun)type).range;
654         }
655         /*else if(type instanceof TApply) {
656             TApply apply1 = (TApply)type;
657             Type f = canonical(apply1.function);
658             if(f instanceof TApply) {
659                 if( canonical(((TApply)f).function) == Types.ARROW ) {
660                     return apply1.parameter;
661                 }
662                 else
663                     return null;
664             }
665             else
666                 return null;
667         }*/
668         else
669             return null;
670     }
671
672     public static int getArity(Type type) {
673         int arity = 0;
674         while(true) {
675             type = getRangeIfFunction(type);
676             if(type == null)
677                 break;
678             ++arity;
679         }
680         return arity;
681     }
682
683     public static TMetaVar metaVar(Kind kind) {
684         return new TMetaVar(kind);
685     }
686
687     public static Type constrained(TPred constraint, Type type) {
688         return new TFun(constraint, Types.NO_EFFECTS, type);
689     }
690
691     public static Type constrained(TPred[] constraints, Type type) {
692         for(int i=constraints.length-1;i>=0;--i)
693             type = constrained(constraints[i], type);
694         return type;
695     }
696
697     public static TMultiApply toMultiApply(Type type) {
698         ArrayList<Type> parameters = new ArrayList<Type>();
699         type = canonical(type);
700         while(type instanceof TApply) {
701             TApply apply = (TApply)type;
702             parameters.add(apply.parameter);
703             type = canonical(apply.function);
704         }
705         Collections.reverse(parameters);
706         return new TMultiApply(type, parameters);
707     }
708
709     public static Type tuple(Type ... parameters) {
710         if(parameters.length == 1)
711             return parameters[0];
712         else
713             return apply(tupleConstructor(parameters.length), parameters);
714     }
715
716     public static TCon tupleConstructor(int arity) {
717         if(arity < 0 || arity == 1)
718             throw new IllegalArgumentException("The arity of a tuple cannot be " + arity + ".");
719
720         TCon[] oldTupleCache = tupleCache;
721         if(oldTupleCache.length <= arity) {         
722             int oldLength = oldTupleCache.length;
723             int newLength = oldLength*2;
724             while(newLength <= arity)
725                 newLength *= 2;
726             TCon[] newTupleCache = Arrays.copyOf(oldTupleCache, newLength);
727             for(int i=oldLength;i<newLength;++i) {
728                 StringBuilder b = new StringBuilder();
729                 b.append('(');
730                 for(int j=1;j<i;++j)
731                     b.append(',');
732                 b.append(')');
733                 newTupleCache[i] = con(BUILTIN, b.toString());
734             }
735             TCon result = newTupleCache[arity];
736             tupleCache = newTupleCache;
737             return result;
738         }
739         else
740             return oldTupleCache[arity];
741     }
742
743     public static void unify(TFun a, TFun b) throws UnificationException {
744         unify(a.domain, b.domain);
745         unify(a.effect, b.effect);
746         unify(a.range, b.range);
747     }
748
749     public static void unify(TApply a, TApply b) throws UnificationException {
750         unify(a.function, b.function);
751         unify(a.parameter, b.parameter);
752     }
753
754     public static void unify(TForAll a, TForAll b) throws UnificationException {
755         try {
756             Kinds.unify(a.var.getKind(), b.var.getKind());
757         } catch (KindUnificationException e) {
758             throw new UnificationException(a, b);
759         }
760         TVar newVar = var(a.var.getKind());
761         unify(a.type.replace(a.var, newVar), b.type.replace(b.var, newVar));
762     }
763
764     public static void unify(TPred a, TPred b) throws UnificationException {
765         if(a.typeClass != b.typeClass
766                 || a.parameters.length != b.parameters.length)
767             throw new UnificationException(a, b);
768         for(int i=0;i<a.parameters.length;++i)
769             unify(a.parameters[i], b.parameters[i]);
770     }
771
772     public static void unify(TUnion a, TUnion b) throws UnificationException {
773         if(a.effects.length != b.effects.length)
774             throw new UnificationException(a, b);
775         for(int i=0;i<a.effects.length;++i)
776             unify(a.effects[i], b.effects[i]);        
777     }
778
779     public static void unify(Type a, Type b) throws UnificationException {
780         a = canonical(a);
781         b = canonical(b);
782         if(a == b)
783             return;
784         if(a instanceof TMetaVar) {
785             ((TMetaVar)a).setRef(b);
786             return;
787         }
788         if(b instanceof TMetaVar) {
789             ((TMetaVar)b).setRef(a);
790             return;
791         }
792         else
793             b = canonical(b);
794         Class<?> ca = a.getClass();
795         Class<?> cb = b.getClass();
796         if(ca != cb) {
797             throw new UnificationException(a, b);
798         }
799         if(ca == TApply.class) 
800             unify((TApply)a, (TApply)b);
801         else if(ca == TFun.class) 
802             unify((TFun)a, (TFun)b);
803         else if(ca == TForAll.class)
804             unify((TForAll)a, (TForAll)b);
805         else if(ca == TPred.class) 
806             unify((TPred)a, (TPred)b);
807         else if(ca == TUnion.class) 
808             unify((TUnion)a, (TUnion)b);
809         else // ca == TCon.class || ca = TVar.class 
810             throw new UnificationException(a, b);
811     }
812
813     public static TVar var(Kind kind) {
814         return new TVar(kind);
815     }
816
817     public static TVar[] vars(TVar[] otherVars) {
818         TVar[] vars = new TVar[otherVars.length];
819         for(int i=0;i<otherVars.length;++i)
820             vars[i] = var(otherVars[i].getKind());
821         return vars;
822     }
823
824     public static Type instantiate(Type type, Type ... parameters) {
825         for(int i=0;i<parameters.length;++i) {
826             type = canonical(type);
827             if(!(type instanceof TForAll))
828                 throw new IllegalArgumentException();
829             TForAll forAll = (TForAll)type;
830             type = forAll.type.replace(forAll.var, parameters[i]);
831         }
832         return type;
833     }
834
835     public static Type[] getTypes(Typed[] values) {
836         Type[] types = new Type[values.length];
837         for(int i=0;i<values.length;++i)
838             types[i] = values[i].getType();
839         return types;                
840     }
841
842     /**
843      * Matches b to a, i.e. finds a substitution such that a[substitution] = b.
844      * Unbound metavariables in b are consired as normal variables. It is assumed
845      * that a does not contain metavariables and b does not contain any type variables
846      * in a (no occurs checks needed).
847      * @param a pattern
848      * @param b instance
849      * @param substitution
850      * @return
851      */
852     public static boolean match(Type a, Type b, THashMap<TVar, Type> substitution) {
853         b = canonical(b);
854
855         Class<?> ca = a.getClass();
856         if(ca == TVar.class) {
857             TVar ta = (TVar)a;
858             Type t = substitution.get(ta);
859             if(t == null) {
860                 substitution.put(ta, b); // no occurs check needed
861                 return true;
862             }
863             else
864                 return match(t, b, substitution);                
865         }        
866         if(a == b)
867             return true;        
868         Class<?> cb = b.getClass();
869         if(ca != cb || ca == TCon.class)
870             return false;
871         if(ca == TApply.class) 
872             return match((TApply)a, (TApply)b, substitution);        
873         else if(ca == TFun.class) 
874             return match((TFun)a, (TFun)b, substitution);
875         else if(ca == TPred.class) 
876             return match((TPred)a, (TPred)b, substitution);
877         else {
878             throw new UnsupportedOperationException("match(" + a + ", " + b +") not supported"); // TForAll not supported
879         }
880     }
881
882     public static boolean match(TApply a, TApply b, THashMap<TVar, Type> substitution) {
883         return match(a.function, b.function, substitution) && match(a.parameter, b.parameter, substitution);
884     }
885
886     public static boolean match(TPred a, TPred b, THashMap<TVar, Type> substitution) {
887         if(a.typeClass != b.typeClass || a.parameters.length != b.parameters.length)
888             return false;
889         for(int i=0;i<a.parameters.length;++i)
890             if(!match(a.parameters[i], b.parameters[i], substitution))
891                 return false;
892         return true;
893     }
894
895     public static boolean match(TFun a, TFun b, THashMap<TVar, Type> substitution) {
896         return match(a.domain, b.domain, substitution) 
897                 && match(a.effect, b.effect, substitution)
898                 && match(a.range, b.range, substitution);
899     }
900
901     public static Type removePred(Type type,
902             ArrayList<TPred> preds) {
903         while(type instanceof TFun) {
904             TFun pred = (TFun)type;
905             if(!(pred.domain instanceof TPred))
906                 break;
907             preds.add((TPred)pred.domain);
908             type = canonical(pred.range);
909         }
910         return type;
911     }
912
913     public static <T extends Typed> Type[] getTypes(List<T> vars) {
914         Type[] result = new Type[vars.size()];
915         for(int i=0;i<result.length;++i)
916             result[i] = vars.get(i).getType();
917         return result;
918     }
919
920     public static boolean isBoxed(Type type) {
921         while(true) {
922             if(type instanceof TVar)
923                 return true;
924             else if(type instanceof TApply) {
925                 TApply apply = (TApply)type;
926                 Type function = Types.canonical(apply.function);
927                 if(function == Types.MAYBE || function == Types.MVECTOR || function == Types.VECTOR) 
928                     // FIXME Special case handled now here.
929                     // The same problem is possibly with other types also!!!
930                     type = apply.parameter;
931                 else
932                     type = function;
933             }
934             else if(type instanceof TMetaVar) {
935                 type = ((TMetaVar)type).ref;
936                 if(type == null)
937                     return true;
938             }
939             else if(type instanceof TForAll) {
940                 type = ((TForAll)type).type;
941             }
942             else
943                 return false;
944         }
945     }
946
947     public static boolean isFunction(Type type) {
948         type = canonical(type);
949         return type instanceof TFun;
950         /*if(!(type instanceof TApply))
951             return false;
952         type = canonical(((TApply)type).function);
953         if(!(type instanceof TApply))
954             return false;
955         type = canonical(((TApply)type).function);
956         return type == ARROW;*/
957     }
958
959     public static boolean equals(Type[] as, Type[] bs) {
960         if(as.length != bs.length)
961             return false;
962         for(int i=0;i<as.length;++i)
963             if(!equals(as[i], bs[i]))
964                 return false;
965         return true;
966     }
967
968     public static String toString(Type[] types) {
969         StringBuilder b = new StringBuilder();
970         TypeUnparsingContext tuc = new TypeUnparsingContext();
971         b.append('[');
972         boolean first = true;
973         for(Type type : types) {
974             if(first)
975                 first = false;
976             else
977                 b.append(", ");
978             b.append(type.toString(tuc));
979         }
980         b.append(']');
981         return b.toString();
982     }
983
984     public static TCon getConstructor(Type type) throws MatchException {
985         while(true) {
986             if(type instanceof TCon)
987                 return (TCon)type;
988             else if(type instanceof TApply)
989                 type = ((TApply)type).function;
990             else if(type instanceof TMetaVar) {
991                 Type ref = ((TMetaVar)type).ref;
992                 if(ref == null)
993                     throw new MatchException();
994                 type = ref;
995             }
996             else
997                 throw new MatchException();
998         }
999     }
1000
1001     public static Type[] replace(Type[] types, TVar[] from, Type[] to) {
1002         if(types.length == 0)
1003             return Type.EMPTY_ARRAY;
1004         Type[] result = new Type[types.length];
1005         for(int i=0;i<types.length;++i)
1006             result[i] = types[i].replace(from, to);
1007         return result;
1008     }
1009     
1010     public static <T extends Type> Type[] replace(Type[] types, THashMap<TVar, T> map) {
1011         if(types.length == 0)
1012             return Type.EMPTY_ARRAY;
1013         Type[] result = new Type[types.length];
1014         for(int i=0;i<types.length;++i)
1015             result[i] = types[i].replace(map);
1016         return result;
1017     }
1018
1019     public static Type union(Type ... effects) {
1020         if(effects.length == 0)
1021             return NO_EFFECTS;
1022         else if(effects.length == 1)
1023             return effects[0];
1024         else
1025             return new TUnion(effects);
1026     }
1027
1028     public static Type union(List<Type> effects) {
1029         if(effects.size() == 0)
1030             return NO_EFFECTS;
1031         else if(effects.size() == 1)
1032             return effects.get(0);
1033         else
1034             return new TUnion(effects.toArray(new Type[effects.size()]));
1035     }
1036
1037     public static void canonize(Type[] types) {
1038         for(int i=0;i<types.length;++i)
1039             types[i] = canonical(types[i]);
1040     }
1041     
1042     public static Type simplifyFinalEffect(Type effect) {
1043         effect = canonical(effect);
1044         if(effect instanceof TMetaVar) {
1045             try {
1046                 //((TMetaVar) effect).setRef(Types.NO_EFFECTS);
1047                 Type t = Types.var(Kinds.EFFECT);
1048                 ((TMetaVar) effect).setRef(t);
1049                 return t;
1050             } catch (UnificationException e) {
1051                 // Should not happen.
1052                 throw new RuntimeException(e);
1053             }
1054         }
1055         if(effect instanceof TUnion) {
1056             TUnion union = (TUnion)effect;
1057             if(union.effects.length == 0)
1058                 return Types.NO_EFFECTS;
1059             ArrayList<Type> effects = new ArrayList<Type>(union.effects.length);
1060             for(Type c : union.effects) {
1061                 c = simplifyFinalEffect(c);
1062                 if(c instanceof TUnion)
1063                     for(Type c2 : ((TUnion)c).effects)
1064                         effects.add(c2);
1065                 else
1066                     effects.add(c);
1067             }
1068             return union(effects);
1069         }
1070         return effect;
1071     }
1072     
1073     public static Type simplifyType(Type effect) {
1074         effect = canonical(effect);
1075         if(effect instanceof TUnion) {
1076             TUnion union = (TUnion)effect;
1077             if(union.effects.length == 0)
1078                 return Types.NO_EFFECTS;
1079             THashSet<Type> effects = new THashSet<Type>(union.effects.length);
1080             for(Type c : union.effects) {
1081                 c = simplifyFinalEffect(c);
1082                 if(c instanceof TUnion)
1083                     for(Type c2 : ((TUnion)c).effects)
1084                         effects.add(c2);
1085                 else
1086                     effects.add(c);
1087             }
1088             return union(effects.toArray(new Type[effects.size()]));
1089         }
1090         return effect;
1091     }
1092
1093     public static Type parseType(ITypeEnvironment environment, String text) throws SCLTypeParseException {
1094         return parseType(new TypeElaborationContext(environment), text);
1095     }
1096
1097     public static Type parseType(ITypeEnvironment environment, THashMap<String, TVar> localTypeVars, String text) throws SCLTypeParseException {
1098         return parseType(new TypeElaborationContext(localTypeVars, environment), text);
1099     }
1100
1101     public static Type parseType(String text) throws SCLTypeParseException {
1102         return parseType(new TypeElaborationContext(DUMMY_TYPE_ENVIRONMENT), text);
1103     }
1104
1105     public static Type parseType(THashMap<String, TVar> localTypeVars, String text) throws SCLTypeParseException {
1106         return parseType(new TypeElaborationContext(localTypeVars, DUMMY_TYPE_ENVIRONMENT), text);
1107     }
1108     
1109     private static Type parseType(TypeElaborationContext context, String text) throws SCLTypeParseException {
1110         SCLParserImpl parser = new SCLParserImpl(new StringReader(text));
1111         try {
1112             org.simantics.scl.compiler.internal.parsing.types.TypeAst ast = 
1113                     (org.simantics.scl.compiler.internal.parsing.types.TypeAst)parser.parseType();
1114             return ast.toType(context);
1115         } catch (SCLSyntaxErrorException e) {
1116             throw new SCLTypeParseException(new Problem(
1117                     Locations.beginOf(e.location),
1118                     Locations.endOf(e.location),
1119                     e.getMessage()));
1120         }
1121     }
1122
1123     public static Type instantiateAndStrip(Type type) {
1124         while(true) {
1125             if(type instanceof TForAll) {
1126                 TForAll forAll = (TForAll)type;
1127                 type = forAll.type.replace(forAll.var, metaVar(forAll.var.getKind()));
1128             }
1129             else if(type instanceof TFun) {
1130                 TFun fun = (TFun)type;
1131                 if(fun.domain instanceof TPred || fun.domain == Types.PUNIT)
1132                     type = fun.range;
1133                 else
1134                     return type;
1135             }
1136             else if(type instanceof TMetaVar) {
1137                 TMetaVar metaVar = (TMetaVar)type;
1138                 if(metaVar.ref == null)
1139                     return type;
1140                 else
1141                     type = metaVar.ref;
1142             }
1143             else
1144                 return type;
1145         }
1146     }
1147     
1148 }