1 package org.simantics.scl.compiler.elaboration.contexts;
3 import java.util.ArrayList;
5 import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;
6 import org.simantics.scl.compiler.common.names.Name;
7 import org.simantics.scl.compiler.constants.NoRepConstant;
8 import org.simantics.scl.compiler.elaboration.expressions.EAmbiguous;
9 import org.simantics.scl.compiler.elaboration.expressions.EApply;
10 import org.simantics.scl.compiler.elaboration.expressions.EConstant;
11 import org.simantics.scl.compiler.elaboration.expressions.EError;
12 import org.simantics.scl.compiler.elaboration.expressions.ELiteral;
13 import org.simantics.scl.compiler.elaboration.expressions.EPlaceholder;
14 import org.simantics.scl.compiler.elaboration.expressions.EVariable;
15 import org.simantics.scl.compiler.elaboration.expressions.Expression;
16 import org.simantics.scl.compiler.elaboration.expressions.Variable;
17 import org.simantics.scl.compiler.elaboration.modules.SCLValue;
18 import org.simantics.scl.compiler.environment.Environment;
19 import org.simantics.scl.compiler.errors.ErrorLog;
20 import org.simantics.scl.compiler.errors.Locations;
21 import org.simantics.scl.compiler.internal.elaboration.constraints.Constraint;
22 import org.simantics.scl.compiler.internal.elaboration.constraints.ConstraintEnvironment;
23 import org.simantics.scl.compiler.internal.elaboration.constraints.ConstraintSolver;
24 import org.simantics.scl.compiler.internal.elaboration.constraints.ExpressionAugmentation;
25 import org.simantics.scl.compiler.internal.elaboration.constraints.ReducedConstraints;
26 import org.simantics.scl.compiler.internal.elaboration.subsumption.SubSolver;
27 import org.simantics.scl.compiler.internal.elaboration.subsumption.Subsumption;
28 import org.simantics.scl.compiler.types.TApply;
29 import org.simantics.scl.compiler.types.TCon;
30 import org.simantics.scl.compiler.types.TForAll;
31 import org.simantics.scl.compiler.types.TFun;
32 import org.simantics.scl.compiler.types.TMetaVar;
33 import org.simantics.scl.compiler.types.TPred;
34 import org.simantics.scl.compiler.types.TUnion;
35 import org.simantics.scl.compiler.types.TVar;
36 import org.simantics.scl.compiler.types.Type;
37 import org.simantics.scl.compiler.types.Types;
38 import org.simantics.scl.compiler.types.exceptions.UnificationException;
39 import org.simantics.scl.compiler.types.kinds.Kinds;
40 import org.simantics.scl.compiler.types.util.TypeUnparsingContext;
42 import gnu.trove.map.hash.THashMap;
43 import gnu.trove.set.hash.THashSet;
45 public class TypingContext implements EnvironmentalContext {
47 private ErrorLog errorLog;
50 private ArrayList<Subsumption> effectSubsumptions = new ArrayList<Subsumption>();
51 private ArrayList<Subsumption> subsumptions = new ArrayList<Subsumption>();
52 private ArrayList<Type> potentialSingletonEffects = new ArrayList<Type>();
55 private ArrayList<Type> effectUpperBounds = new ArrayList<Type>();
58 private ArrayList<EVariable> constraintDemand = new ArrayList<EVariable>();
59 private ArrayList<Variable[]> constraintFrames = new ArrayList<Variable[]>();
62 private boolean isInPattern;
65 public THashSet<SCLValue> recursiveValues;
66 public ArrayList<EPlaceholder> recursiveReferences;
69 public ArrayList<EAmbiguous> overloadedExpressions = new ArrayList<EAmbiguous>();
71 //TypeUnparsingContext tuc = new TypeUnparsingContext();
73 Environment environment;
74 THashMap<Name, SCLValue> constants = new THashMap<Name, SCLValue>();
76 public TypingContext(ErrorLog errorLog, Environment environment) {
77 this.errorLog = errorLog;
78 this.environment = environment;
82 * Records the fact that {@code a} should be a subeffect
83 * of {@code b}. Only types {@code TMetaVar}, {@code TVar}, {@code TCon}, {@code TUnion}
86 public void subsumeEffect(long loc, Type a, Type b) {
87 a = Types.canonical(a);
88 if(a == Types.NO_EFFECTS)
90 b = Types.canonical(b);
93 if(b == Types.NO_EFFECTS) {
95 Types.unify(a, Types.NO_EFFECTS);
96 } catch(UnificationException e) {
97 errorLog.log(loc, "No side-effects allowed here.");
102 //System.out.println("subsumeEffect(" + a.toString(tuc) + ", " + b.toString(tuc) + ")");
104 /*if(a instanceof TUnion) {
105 TUnion union = (TUnion)a;
106 for(Type e : union.effects)
107 subsumeEffect(loc, e, b);
110 effectSubsumptions.add(new Subsumption(loc, a, b));
113 public void subsume(long loc, Type a, Type b) throws UnificationException {
114 a = Types.canonical(a);
115 b = Types.canonical(b);
119 //System.out.println("subsume(" + a.toString(tuc) + ", " + b.toString(tuc) + ")");
121 if(a instanceof TMetaVar) {
122 TMetaVar aVar = (TMetaVar)a;
123 if(b instanceof TMetaVar)
124 subsumptions.add(new Subsumption(loc, a, b));
127 throw new UnificationException(a, b);
128 aVar.setRef(createSubtypeTemplate(loc, b));
132 else if(b instanceof TMetaVar) {
133 TMetaVar bVar = (TMetaVar)b;
135 throw new UnificationException(a, b);
136 bVar.setRef(createSupertypeTemplate(loc, a));
139 if(a instanceof TFun) {
140 if(!(b instanceof TFun))
141 throw new UnificationException(a, b);
144 subsume(loc, bFun.domain, aFun.domain);
145 subsumeEffect(loc, aFun.effect, bFun.effect);
146 subsume(loc, aFun.range, bFun.range);
148 else if(a instanceof TApply) {
151 else if(a instanceof TPred) {
154 else // a instanceof TUnion
155 throw new UnificationException(a, b);
159 * Creates a template for all subtypes of the given type
160 * where all possible varying types are replaced by metavars
161 * with properly set inequalities.
163 private Type createSubtypeTemplate(long loc, Type type) {
164 type = Types.canonical(type);
165 if(type instanceof TCon)
167 else if(type instanceof TApply)
169 else if(type instanceof TPred)
171 else if(type instanceof TFun) {
172 TFun fun = (TFun)type;
173 Type funEffect = Types.canonical(fun.effect);
175 if(funEffect == Types.NO_EFFECTS)
176 effect = Types.NO_EFFECTS;
178 effect = Types.metaVar(Kinds.EFFECT);
179 effectSubsumptions.add(new Subsumption(loc, effect, funEffect));
181 return Types.functionE(
182 createSupertypeTemplate(loc, fun.domain),
184 createSubtypeTemplate(loc, fun.range));
186 else if(type instanceof TMetaVar) {
187 TMetaVar var = (TMetaVar)type;
188 TMetaVar newVar = Types.metaVar(var.getKind());
189 subsumptions.add(new Subsumption(loc, newVar, var));
192 else if(type instanceof TVar)
194 else if(type instanceof TUnion) {
195 TUnion union = (TUnion)type;
196 if(union.isMinimal())
198 TMetaVar newVar = Types.metaVar(Kinds.EFFECT);
199 subsumptions.add(new Subsumption(loc, newVar, type));
202 else if(type instanceof TForAll) {
203 TForAll forAll = (TForAll)type;
204 Type t = createSubtypeTemplate(loc, forAll.type);
208 return Types.forAll(forAll.var, t);
211 throw new InternalCompilerError("Unsupported type " + type + ".");
215 * Creates a template for all supertypes of the given type
216 * where all possible varying types are replaced by metavars
217 * with properly set inequalities.
219 private Type createSupertypeTemplate(long loc, Type type) {
220 type = Types.canonical(type);
221 if(type instanceof TCon)
223 else if(type instanceof TApply)
225 else if(type instanceof TPred)
227 else if(type instanceof TFun) {
228 TFun fun = (TFun)type;
229 TMetaVar effect = Types.metaVar(Kinds.EFFECT);
230 effectSubsumptions.add(new Subsumption(loc, fun.effect, effect));
231 return Types.functionE(
232 createSubtypeTemplate(loc, fun.domain),
234 createSupertypeTemplate(loc, fun.range));
236 else if(type instanceof TMetaVar) {
237 TMetaVar var = (TMetaVar)type;
238 TMetaVar newVar = Types.metaVar(var.getKind());
239 subsumptions.add(new Subsumption(loc, var, newVar));
242 else if(type instanceof TVar)
244 else if(type instanceof TUnion) {
245 TMetaVar newVar = Types.metaVar(Kinds.EFFECT);
246 subsumptions.add(new Subsumption(loc, type, newVar));
249 else if(type instanceof TForAll) {
250 TForAll forAll = (TForAll)type;
251 Type t = createSupertypeTemplate(loc, forAll.type);
255 return Types.forAll(forAll.var, t);
258 throw new InternalCompilerError("Unsupported type " + type + ".");
262 * Instantiates type abstractions and constraints from the value.
264 public Expression instantiate(Expression expr) {
265 Type type = Types.canonical(expr.getType());
266 while(type instanceof TForAll) {
267 TForAll forAll = (TForAll)type;
268 TVar var = forAll.var;
269 TMetaVar mVar = Types.metaVar(var.getKind());
270 type = Types.canonical(forAll.type).replace(var, mVar);
271 expr = expr.applyType(mVar);
273 while(type instanceof TFun) {
274 TFun fun = (TFun)type;
275 if(fun.domain instanceof TPred) { // No need to canonicalize
276 TPred pred = (TPred)fun.domain;
279 long loc = expr.getLocation();
280 EVariable var = new EVariable(loc, null);
282 expr = new EApply(loc, expr, var);
283 addConstraintDemand(var);
285 else if(fun.domain == Types.PUNIT) {
288 long loc = expr.getLocation();
289 declareEffect(expr.location, fun.effect);
290 expr = new EApply(loc, fun.effect, expr, new ELiteral(loc, NoRepConstant.PUNIT));
300 * Enforces {@code expr} to have type {@code b} by adding
301 * type applications, lambdas and effect subsumptions.
303 public Expression subsume(Expression expr, Type b) {
304 b = Types.canonical(b);
305 /*if(b instanceof TForAll) {
306 TForAll forAll = (TForAll)b;
307 TVar var = forAll.var;
308 TVar newVar = Types.var(var.getKind());
309 b = Types.canonical(forAll.type).replace(var, newVar);
310 return new ELambdaType(new TVar[] {newVar}, subsume(expr, b));
312 expr = instantiate(expr);
315 subsume(expr.getLocation(), expr.getType(), b);
316 } catch(UnificationException e) {
317 typeError(expr.getLocation(), b, expr.getType());
322 private boolean expandSubsumptions() {
323 boolean nontrivialSubs = true;
324 int iterationCount = 0;
325 while(!subsumptions.isEmpty() && nontrivialSubs) {
326 ArrayList<Subsumption> oldSubsumptions = subsumptions;
327 subsumptions = new ArrayList<Subsumption>();
328 nontrivialSubs = false;
329 for(Subsumption sub : oldSubsumptions) {
330 Type a = sub.a = Types.canonical(sub.a);
331 Type b = sub.b = Types.canonical(sub.b);
332 if(b instanceof TMetaVar && a instanceof TMetaVar) {
333 subsumptions.add(sub);
337 subsume(sub.loc, a, b);
338 } catch (UnificationException e) {
339 errorLog.log(sub.loc, "Type " + a + " is not a subtype of " + b + ".");
341 nontrivialSubs = true;
345 if(iterationCount == 5) {
346 // Test that the skeletons are unifiable
347 THashMap<TMetaVar,TMetaVar> metaVarMap =
348 new THashMap<TMetaVar,TMetaVar>();
349 ArrayList<Subsumption> subCopies = new ArrayList<Subsumption>(subsumptions.size());
350 for(Subsumption sub : subsumptions)
352 subCopies.add(new Subsumption(sub.loc,
353 sub.a.copySkeleton(metaVarMap), sub.b.copySkeleton(metaVarMap)));
355 /*System.out.println("----");
356 TypeUnparsingContext tuc = new TypeUnparsingContext();
357 for(Subsumption sub : subCopies)
358 System.out.println(sub.a.toString(tuc) + " == " + sub.b.toString(tuc));*/
360 for(Subsumption sub : subCopies)
362 Types.unify(sub.a, sub.b);
363 } catch (UnificationException e) {
364 errorLog.log(sub.loc, "Unification of types failed.");
368 /*System.out.println("----");
369 for(Subsumption sub : subCopies)
370 System.out.println(sub.a.toString(tuc) + " === " + sub.b.toString(tuc));*/
373 for(Subsumption sub : subsumptions)
375 // FIXME This is not correct in all cases, should emit unsolved subsumptions to the type of the value
376 Types.unify(sub.a, sub.b);
377 } catch (UnificationException e) {
378 // Should not happen. Both types should be metavars.
379 throw new InternalCompilerError();
381 subsumptions.clear();
385 private boolean isEffect(Type type) {
386 if(type instanceof TMetaVar)
387 return ((TMetaVar)type).getKind() == Kinds.EFFECT;
388 else if(type instanceof TCon)
389 return environment.getTypeConstructor((TCon)type).kind == Kinds.EFFECT;
390 else if(type instanceof TVar)
391 return ((TVar)type).getKind() == Kinds.EFFECT;
392 else if(type instanceof TUnion)
399 public void solveSubsumptions(long globalLoc) {
400 if(expandSubsumptions())
401 new SubSolver(errorLog, effectSubsumptions, potentialSingletonEffects, globalLoc).solve();
404 public void declareEffect(long loc, Type effect) {
405 subsumeEffect(loc, effect, effectUpperBounds.get(effectUpperBounds.size()-1));
408 public void pushEffectUpperBound(long loc, Type effect) {
409 effectUpperBounds.add(effect);
410 potentialSingletonEffects.add(effect);
413 public Type popEffectUpperBound() {
414 return effectUpperBounds.remove(effectUpperBounds.size()-1);
417 public ErrorLog getErrorLog() {
421 public boolean isInPattern() {
425 public void setInPattern(boolean isInPattern) {
426 this.isInPattern = isInPattern;
429 public void pushConstraintFrame(Variable[] array) {
430 constraintFrames.add(array);
433 public void popConstraintFrame() {
434 constraintFrames.remove(constraintFrames.size()-1);
437 public void addConstraintDemand(EVariable var) {
438 for(int i=constraintFrames.size()-1;i>=0;--i)
439 for(Variable con : constraintFrames.get(i))
440 if(Types.equals(var.getType(), con.getType())) {
441 var.setVariable(con);
444 constraintDemand.add(var);
447 public Expression addConstraint(TPred pred) {
448 EVariable evidence = new EVariable(null);
449 evidence.setType(pred);
450 addConstraintDemand(evidence);
454 public Expression[] addConstraints(TPred[] preds) {
455 if(preds.length == 0)
456 return Expression.EMPTY_ARRAY;
457 Expression[] evidences = new Expression[preds.length];
458 for(int i=0;i<preds.length;++i)
459 evidences[i] = addConstraint(preds[i]);
463 public ArrayList<EVariable> getConstraintDemand() {
464 return constraintDemand;
467 public void resetConstraintDemand() {
468 constraintDemand = new ArrayList<EVariable>();
471 public void typeError(long loc, Type requiredType, Type givenType) {
472 TypeUnparsingContext tuc = new TypeUnparsingContext();
473 errorLog.log(loc, "Expected <" + requiredType.toString(tuc) + "> got <" + givenType.toString(tuc) + ">.");
476 public Expression solveConstraints(Environment environment, Expression expression) {
477 ArrayList<EVariable> constraintDemand = getConstraintDemand();
478 if(!constraintDemand.isEmpty()) {
479 ConstraintEnvironment ce = new ConstraintEnvironment(environment);
480 ReducedConstraints red = ConstraintSolver.solve(
481 ce, new ArrayList<TPred>(0), constraintDemand,
484 expression = ExpressionAugmentation.augmentSolved(
485 red.solvedConstraints,
488 for(Constraint c : red.unsolvedConstraints)
489 errorLog.log(c.getDemandLocation(), "There is no instance for <"+c.constraint+">.");
492 expression = expression.decomposeMatching();
497 public SCLValue getValue(Name name) {
498 if(constants.containsKey(name))
499 return constants.get(name);
500 SCLValue value = environment.getValue(name);
502 errorLog.log(Locations.NO_LOCATION, "Couldn't find " + name + ".");
503 constants.put(name, value);
507 public Expression getConstant(Name name, Type ... typeParameters) {
508 SCLValue value = getValue(name);
510 return new EError(Locations.NO_LOCATION);
511 return new EConstant(value, typeParameters);
514 public Environment getEnvironment() {