--- /dev/null
+package org.simantics.scl.compiler.internal.elaboration.constraints;
+
+import gnu.trove.map.hash.THashMap;
+import gnu.trove.set.hash.THashSet;
+
+import java.util.ArrayList;
+
+import org.simantics.scl.compiler.elaboration.expressions.ELiteral;
+import org.simantics.scl.compiler.elaboration.expressions.EVariable;
+import org.simantics.scl.compiler.elaboration.expressions.Variable;
+import org.simantics.scl.compiler.errors.Locations;
+import org.simantics.scl.compiler.types.TCon;
+import org.simantics.scl.compiler.types.TPred;
+import org.simantics.scl.compiler.types.Types;
+
+class ConstraintSet {
+
+ private static int id = 0;
+
+ final ConstraintEnvironment environment;
+
+ /**
+ * Collection of all active (solved or unsolved) constraints.
+ */
+ final THashMap<TCon, ArrayList<Constraint>> constraints = new THashMap<TCon, ArrayList<Constraint>>();
+
+ /**
+ * Set of currently unsolved constraints.
+ */
+ THashSet<Constraint> unsolved = new THashSet<Constraint>();
+
+ /**
+ * These are constraints that are explicitly required in the code
+ */
+ final ArrayList<Constraint> needed = new ArrayList<Constraint>();
+
+ public ConstraintSet(ConstraintEnvironment environment) {
+ this.environment = environment;
+ }
+
+ private ArrayList<Constraint> getConstraintList(TCon typeClass) {
+ ArrayList<Constraint> cl = constraints.get(typeClass);
+ if(cl == null) {
+ cl = new ArrayList<Constraint>(2);
+ constraints.put(typeClass, cl);
+ }
+ return cl;
+ }
+
+ public void addDemand(EVariable demand) {
+ Constraint constraint = addConstraint(demand.getLocation(), (TPred)demand.getType());
+ demand.setVariable(constraint.evidence);
+ needed.add(constraint);
+ }
+
+ private Constraint addConstraint(long demandLocation, TPred constraint) {
+ ArrayList<Constraint> cl = getConstraintList(constraint.typeClass);
+ for(Constraint c : cl) {
+ if(Types.equals(constraint, c.constraint)) {
+ return c;
+ }
+ }
+ Constraint newConstraint = newConstraint(demandLocation, constraint);
+ cl.add(newConstraint);
+ unsolved.add(newConstraint);
+ return newConstraint;
+ }
+
+ private void addSuperconstraints(Constraint constraint) {
+ scloop: for(Superconstraint superconstraint : environment.getSuperconstraints(constraint.constraint)) {
+ TPred sc = superconstraint.superconstraint;
+ ArrayList<Constraint> cl = getConstraintList(sc.typeClass);
+ for(Constraint c : cl) {
+ if(c.state < Constraint.STATE_HAS_SUBCLASS &&
+ Types.equals(sc, c.constraint)) {
+ unsolved.remove(c);
+ c.setGenerator(Constraint.STATE_HAS_SUBCLASS,
+ new ELiteral(constraint.demandLocation, superconstraint.generator), constraint.constraint.parameters, constraint);
+ continue scloop;
+ }
+ }
+ Constraint newConstraint = newConstraint(constraint.demandLocation, sc);
+ newConstraint.setGenerator(Constraint.STATE_HAS_SUBCLASS,
+ new ELiteral(constraint.demandLocation, superconstraint.generator), constraint.constraint.parameters, constraint);
+ cl.add(newConstraint);
+ }
+ }
+
+ private Constraint newConstraint(long demandLocation, TPred constraint) {
+ Variable evidence = new Variable("ev" + (++id));
+ evidence.setType(constraint);
+ Constraint newConstraint = new Constraint(constraint, evidence, demandLocation);
+ addSuperconstraints(newConstraint);
+ return newConstraint;
+ }
+
+ public void reduce() {
+ while(!unsolved.isEmpty()) {
+ THashSet<Constraint> temp = unsolved;
+ unsolved = new THashSet<Constraint>();
+ for(Constraint c : temp) {
+ if(c.state == Constraint.STATE_UNSOLVED) {
+ Reduction reduction = environment.reduce(c.constraint);
+ if(reduction != null) {
+ TPred[] demands = reduction.demands;
+ if(demands.length == 0)
+ c.setGenerator(Constraint.STATE_HAS_INSTANCE, reduction.generator, reduction.parameters, Constraint.EMPTY_ARRAY);
+ else {
+ Constraint[] dependsOn = new Constraint[demands.length];
+ for(int i=0;i<demands.length;++i)
+ dependsOn[i] = addConstraint(c.demandLocation, demands[i]);
+ c.setGenerator(Constraint.STATE_HAS_INSTANCE, reduction.generator, reduction.parameters, dependsOn);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ public void collect(ArrayList<Constraint> unsolvedConstraints, ArrayList<Constraint> solvedConstraints) {
+ for(Constraint n : needed)
+ n.collect(environment, unsolvedConstraints, solvedConstraints);
+ }
+
+ public Constraint addGiven(TPred c) {
+ Constraint result = addConstraint(Locations.NO_LOCATION, c);
+ result.state = Constraint.STATE_GIVEN;
+ result.generator = Constraint.GIVEN_GENERATOR;
+ return result;
+ }
+}