001: /**************************************************************************/
002: /* B O S S A */
003: /* A simple imperative object-oriented research language */
004: /* (c) Daniel Bonniot 1999 */
005: /* */
006: /* This program is free software; you can redistribute it and/or modify */
007: /* it under the terms of the GNU General Public License as published by */
008: /* the Free Software Foundation; either version 2 of the License, or */
009: /* (at your option) any later version. */
010: /* */
011: /**************************************************************************/package mlsub.typing;
012:
013: import mlsub.typing.lowlevel.Kind;
014:
015: /**
016: * A monotype variable.
017: *
018: * @author Daniel Bonniot
019: */
020:
021: public final class MonotypeVar extends Monotype implements
022: mlsub.typing.lowlevel.Element, TypeSymbol {
023: public MonotypeVar() {
024: }
025:
026: public MonotypeVar(boolean existential) {
027: this .existential = existential;
028: }
029:
030: public MonotypeVar(String name) {
031: this .name = name;
032: }
033:
034: private MonotypeVar(String name, Kind persistentKind) {
035: this .name = name;
036: setPersistentKind(persistentKind);
037: }
038:
039: private String name;
040:
041: public String getName() {
042: return name;
043: }
044:
045: public TypeSymbol cloneTypeSymbol() {
046: return new MonotypeVar(name, persistentKind);
047: }
048:
049: /**
050: * Perform type symbol substitution inside the monotype.
051: *
052: * Does not need to create a new object, but must not
053: * imperatively modify the monotype.
054: *
055: * @param map a map from TypeSymbols to TypeSymbols
056: * @return a monotype with substitution performed
057: */
058: Monotype substitute(java.util.Map map) {
059: Object newVar = map.get(this );
060: if (newVar == null)
061: return this ;
062:
063: return (Monotype) newVar;
064: }
065:
066: /****************************************************************
067: * Fresh monotype variables
068: ****************************************************************/
069:
070: public static MonotypeVar[] news(int n) {
071: return news(n, false);
072: }
073:
074: static MonotypeVar[] news(int n, boolean existential) {
075: if (n == 0)
076: return null;
077:
078: MonotypeVar[] res = new MonotypeVar[n];
079: for (int i = 0; i < n; i++) {
080: res[i] = new MonotypeVar(existential);
081: res[i].setPersistentKind(NullnessKind.instance);
082: }
083: return res;
084: }
085:
086: /****************************************************************
087: * low-level interface
088: ****************************************************************/
089:
090: private int id = -1;
091:
092: public int getId() {
093: return id;
094: }
095:
096: public void setId(int value) {
097: id = value;
098: }
099:
100: Kind kind;
101:
102: public Kind getKind() {
103: return kind;
104: }
105:
106: public void setKind(Kind value) {
107: // it is ok to reset kind to null
108: if (kind != null && value != null && kind != value) //TODO: not sure if this case is OK to happen
109: throw new InternalError(
110: "Variance already set in MonotypeVar " + this
111: + ":\nkind was " + kind + ", value is "
112: + value);
113:
114: if (kind == value)
115: return;
116:
117: kind = value;
118: if (value == null) {
119: // Reset the equivalent field so that
120: // this variable becomes "free" again
121: equivalent = null;
122: id = -1;
123: } else {
124: // Do the appropriate cast
125: equivalent = value.freshMonotype(existential);
126: if (Typing.dbg)
127: Debug.println("Equivalence: " + this + " == "
128: + equivalent);
129:
130: // equivalent is null if the kind is that of unconstrained variables
131: if (equivalent != null) {
132: // set the name for debug or display purposes
133: TypeConstructor tc = equivalent.head();
134: if (tc != null)
135: tc.name = this + "'";
136: }
137: }
138: }
139:
140: /** Allows modifying the existing kind. Use in special cases only. */
141: public void resetKind(Kind value) {
142: setKind(null);
143: setKind(value);
144: }
145:
146: public void setPersistentKind(Kind k) {
147: if (persistentKind == k)
148: return;
149:
150: persistentKind = k;
151: if (k == NullnessKind.instance) {
152: kind = k;
153: equivalent = NullnessKind.instance
154: .persistentFreshMonotype(this );
155: }
156: }
157:
158: Kind persistentKind;
159:
160: void reset() {
161: unknown = false;
162:
163: if (persistentKind == null) {
164: setKind(null);
165: } else if (existential) {
166: equivalent = null;
167: kind = null;
168: setKind(persistentKind);
169: } else if (equivalent != null) {
170: if (persistentKind == NullnessKind.instance) {
171: MonotypeConstructor mc = (MonotypeConstructor) equivalent();
172:
173: TypeConstructor tc = mc.getTC();
174: // Reassign a new id
175: NullnessKind.introduce(tc);
176:
177: MonotypeVar raw = (MonotypeVar) mc.getTP()[0];
178: raw.reset();
179: mlsub.typing.lowlevel.Engine.register(raw);
180: }
181: }
182: }
183:
184: /**
185: True when this variable was created during the decomposition of T
186: into T0<T1,...> caused by a constraint A<B1,...> <: T
187: This a priori implies T1 = B1 (supposing A is invariant, but the
188: allowUnknown variable marks that T1=? (UnknownMonotype) is also a
189: valid solution.
190: */
191: private boolean allowUnknown = false;
192:
193: /**
194: Allow this type's type parameters to be changed to the unknown type.
195: */
196: public void allowUnknownTypeParameters() {
197: if (equivalent instanceof MonotypeConstructor) {
198: MonotypeVar[] tps = (MonotypeVar[]) ((MonotypeConstructor) equivalent)
199: .getTP();
200: if (tps != null)
201: for (int i = 0; i < tps.length; i++) {
202: tps[i].allowUnknown = true;
203: if (tps[i].equivalent != null)
204: tps[i].allowUnknownTypeParameters();
205: }
206: }
207: }
208:
209: private boolean unknown;
210:
211: public boolean isUnknown() {
212: return unknown;
213: }
214:
215: public void setUnknown(boolean leq, boolean geq)
216: throws mlsub.typing.lowlevel.Unsatisfiable {
217: if (equivalent != null) {
218: if (kind == NullnessKind.instance) {
219: Monotype raw = ((MonotypeConstructor) equivalent())
220: .getTP()[0];
221: raw.setUnknown(leq, geq);
222: } else {
223: if (!allowUnknown)
224: throw mlsub.typing.lowlevel.LowlevelUnsatisfiable.instance;
225: }
226: }
227:
228: equivalent = UnknownMonotype.instance;
229: persistentKind = null;
230: this .unknown = true;
231: }
232:
233: /** When this variable is discovered to be of some given kind,
234: an equivalent monotype is created. */
235: private Monotype equivalent;
236:
237: // overrides Monotype.equivalent()
238: public Monotype equivalent() {
239: if (equivalent != null)
240: return equivalent;
241: else
242: return this ;
243: }
244:
245: /**
246: Return the head type constructor if this monotype is
247: of a known variance, or null.
248: */
249: public TypeConstructor head() {
250: if (equivalent != null)
251: return equivalent.head();
252: else
253: return null;
254: }
255:
256: private boolean existential;
257:
258: public void setExistential() {
259: existential = true;
260: }
261:
262: public boolean isExistential() {
263: return existential;
264: }
265:
266: /****************************************************************
267: * Misc.
268: ****************************************************************/
269:
270: public String toString() {
271: if (name == null)
272: name = newUniqueName();
273:
274: return name;
275: }
276:
277: private static int uniqueNum = 0;
278:
279: private static String newUniqueName() {
280: return "t" + (uniqueNum++);
281: }
282:
283: /****************************************************************
284: * Simplification
285: ****************************************************************/
286:
287: void tag(int variance) {
288: if (equivalent != null)
289: equivalent.tag(variance);
290: // A type var with kind TopKind will be equivalent to Top, no need to tag.
291: else if (kind != TopMonotype.TopKind.instance)
292: mlsub.typing.lowlevel.Engine.tag(this , variance);
293: }
294:
295: Monotype canonify() {
296: if (equivalent != null)
297: return equivalent.canonify();
298: if (isUnknown())
299: return UnknownMonotype.instance;
300: // A type var with kind TopKind is equivalent to Top.
301: else if (kind == TopMonotype.TopKind.instance)
302: return TopMonotype.instance;
303: else
304: return (MonotypeVar) mlsub.typing.lowlevel.Engine
305: .canonify(this);
306: }
307: }
|