1 package org.simantics.scl.compiler.types;
3 import java.util.ArrayList;
5 import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;
6 import org.simantics.scl.compiler.environment.Environment;
7 import org.simantics.scl.compiler.internal.types.HashCodeUtils;
8 import org.simantics.scl.compiler.internal.types.TypeHashCodeContext;
9 import org.simantics.scl.compiler.internal.types.ast.TVarAst;
10 import org.simantics.scl.compiler.internal.types.ast.TypeAst;
11 import org.simantics.scl.compiler.types.exceptions.KindUnificationException;
12 import org.simantics.scl.compiler.types.exceptions.UnificationException;
13 import org.simantics.scl.compiler.types.kinds.KMetaVar;
14 import org.simantics.scl.compiler.types.kinds.Kind;
15 import org.simantics.scl.compiler.types.kinds.Kinds;
16 import org.simantics.scl.compiler.types.util.Polarity;
17 import org.simantics.scl.compiler.types.util.TypeUnparsingContext;
19 import gnu.trove.map.hash.THashMap;
20 import gnu.trove.set.hash.THashSet;
25 * A meta-variable, a type that is currently unknown. This class
26 * should occur only during type inference. Method removeMetaVars
27 * can be used to remove all instances of TMetaVar from the type.
29 * @author Hannu Niemistö
31 public class TMetaVar extends Type {
32 public static final TMetaVar[] EMPTY_ARRAY = new TMetaVar[0];
33 public static final boolean DEBUG = false;
36 Type skeletonRef = null;
37 Polarity polarity = Polarity.NO_POLARITY;
39 private TMetaVarListener listener;
41 public static abstract class TMetaVarListener {
42 private Object prev; // TMetaVarListener or TMetaVar
43 private TMetaVarListener next;
45 public abstract void notifyAboutChange();
47 public void remove() {
49 return; // Not added or not anymore listening TMetaVar
50 if(prev instanceof TMetaVar)
51 ((TMetaVar)prev).listener = next;
53 ((TMetaVarListener)prev).next = next;
66 TMetaVar(Kind kind, Polarity polarity) {
68 this.polarity = polarity;
71 public Kind getKind() {
72 if(kind instanceof KMetaVar)
73 kind = Kinds.canonical(kind);
78 public Type replace(TVar var, Type replacement) {
82 Type newRef = ref.replace(var, replacement);
86 // We could also return newRef here, but in this way
87 // we don't have to copy so many parent types.
93 public TypeAst toTypeAst(TypeUnparsingContext context) {
95 return new TVarAst(/*polarity.getSymbol() +*/ context.getName(this));
97 return ref.toTypeAst(context);
101 public int hashCode() {
103 return System.identityHashCode(this);
105 return ref.hashCode();
109 public void updateHashCode(TypeHashCodeContext context) {
111 context.append(System.identityHashCode(this));
113 ref.updateHashCode(context);
117 public void collectFreeVars(ArrayList<TVar> vars) {
119 ref.collectFreeVars(vars);
123 public void collectMetaVars(ArrayList<TMetaVar> vars) {
127 ref.collectMetaVars(vars);
131 public void collectMetaVars(THashSet<TMetaVar> vars) {
135 ref.collectMetaVars(vars);
139 public void collectEffectMetaVars(ArrayList<TMetaVar> vars) {
141 ref.collectEffectMetaVars(vars);
144 public void setRef(Type type) throws UnificationException {
146 System.out.println("setRef " + System.identityHashCode(this) + " -> " + type);
148 throw new InternalCompilerError("Method setRef should be called only for unbound meta variables.");
149 if(type.contains(this))
150 throw new UnificationException(this, type);
152 if(polarity != Polarity.NO_POLARITY)
153 type.addPolarity(polarity);
154 if(skeletonRef != null) {
155 Type skeleton = skeletonRef;
157 Skeletons.unifySkeletons(skeleton, type);
159 fireNotifyAboutChange();
162 public Type getRef() {
167 public boolean contains(TMetaVar other) {
169 return ref.contains(other);
170 else if(skeletonRef != null)
171 return skeletonRef.contains(other);
173 return this == other;
177 public Type convertMetaVarsToVars() {
179 if(kind == Kinds.EFFECT && !polarity.isNegative())
180 ref = Types.NO_EFFECTS;
182 ref = Types.var(getKind());
186 return ref.convertMetaVarsToVars();
190 public boolean isGround() {
194 return ref.isGround();
197 public Kind inferKind(Environment context) throws KindUnificationException {
198 return Kinds.metaVar();
202 public boolean containsMetaVars() {
206 return ref.containsMetaVars();
210 public void toName(TypeUnparsingContext context, StringBuilder b) {
212 ref.toName(context, b);
214 b.append(context.getName(this));
218 public int getClassId() {
223 public boolean isMaximal() {
224 return ref != null && ref.isMaximal();
228 public boolean isMinimal() {
229 return ref != null && ref.isMinimal();
233 public void addPolarity(Polarity polarity) {
235 ref.addPolarity(polarity);
237 this.polarity = this.polarity.add(polarity);
240 public Polarity getPolarity() {
245 public void collectConcreteEffects(ArrayList<TCon> concreteEffects) {
247 ref.collectConcreteEffects(concreteEffects);
259 public Type copySkeleton(THashMap<TMetaVar, TMetaVar> metaVarMap) {
261 return ref.copySkeleton(metaVarMap);
263 TMetaVar result = metaVarMap.get(this);
265 result = new TMetaVar(kind, polarity);
266 metaVarMap.put(this, result);
272 public void setSkeletonRef(Type type) throws UnificationException {
274 System.out.println("setSkeletonRef " + System.identityHashCode(this) + " -> " + type);
275 if(ref != null || skeletonRef != null)
276 throw new InternalCompilerError("Method setRef should be called only for unbound meta variables.");
277 if(type.contains(this))
278 throw new UnificationException(this, type);
279 this.skeletonRef = type;
280 fireNotifyAboutChange();
284 public int hashCode(int hash) {
286 return HashCodeUtils.update(hash, System.identityHashCode(this));
288 return ref.hashCode(hash);
292 public int hashCode(int hash, TVar[] boundVars) {
294 return HashCodeUtils.update(hash, System.identityHashCode(this));
296 return ref.hashCode(hash, boundVars);
300 public boolean equalsCanonical(Type other) {
301 return this == other;
305 public Type canonical() {
309 return ref = ref.canonical();
312 public void addListener(TMetaVarListener newListener) {
314 System.out.println("addListener " + System.identityHashCode(this));
315 newListener.next = listener;
316 newListener.prev = this;
318 listener.prev = newListener;
319 listener = newListener;
322 private void fireNotifyAboutChange() {
324 System.out.println("fireNotifyAboutChange " + System.identityHashCode(this) + " " + ref);
325 TMetaVarListener cur = listener;
329 System.out.println(" call listener");
330 cur.prev = null; // This prevents TMetaVarListener.remove from doing anything
331 cur.notifyAboutChange();
332 TMetaVarListener next = cur.next;
338 public TMetaVarListener getLatestListener() {
343 public Kind getKind(Environment context) {