+package org.simantics.scl.compiler.compilation;
+
+import static org.simantics.scl.compiler.elaboration.expressions.Expressions.apply;
+import static org.simantics.scl.compiler.elaboration.expressions.Expressions.applyTypes;
+import static org.simantics.scl.compiler.elaboration.expressions.Expressions.lambda;
+import static org.simantics.scl.compiler.elaboration.expressions.Expressions.loc;
+import static org.simantics.scl.compiler.elaboration.expressions.Expressions.vars;
+import gnu.trove.map.hash.THashMap;
+import gnu.trove.map.hash.TObjectIntHashMap;
+import gnu.trove.set.hash.THashSet;
+import gnu.trove.set.hash.TIntHashSet;
+
+import java.util.ArrayList;
+
+import org.simantics.scl.compiler.elaboration.contexts.TypingContext;
+import org.simantics.scl.compiler.elaboration.expressions.EPlaceholder;
+import org.simantics.scl.compiler.elaboration.expressions.EVariable;
+import org.simantics.scl.compiler.elaboration.expressions.Expression;
+import org.simantics.scl.compiler.elaboration.expressions.Variable;
+import org.simantics.scl.compiler.elaboration.modules.SCLValue;
+import org.simantics.scl.compiler.elaboration.rules.MappingRelation;
+import org.simantics.scl.compiler.elaboration.rules.TransformationRule;
+import org.simantics.scl.compiler.environment.Environment;
+import org.simantics.scl.compiler.errors.ErrorLog;
+import org.simantics.scl.compiler.errors.Locations;
+import org.simantics.scl.compiler.internal.elaboration.constraints.Constraint;
+import org.simantics.scl.compiler.internal.elaboration.constraints.ConstraintEnvironment;
+import org.simantics.scl.compiler.internal.elaboration.constraints.ConstraintSolver;
+import org.simantics.scl.compiler.internal.elaboration.constraints.ExpressionAugmentation;
+import org.simantics.scl.compiler.internal.elaboration.constraints.ReducedConstraints;
+import org.simantics.scl.compiler.internal.elaboration.utils.StronglyConnectedComponents;
+import org.simantics.scl.compiler.module.ConcreteModule;
+import org.simantics.scl.compiler.types.TPred;
+import org.simantics.scl.compiler.types.TVar;
+import org.simantics.scl.compiler.types.Type;
+import org.simantics.scl.compiler.types.Types;
+import org.simantics.scl.compiler.types.kinds.Kinds;
+import org.simantics.scl.compiler.types.util.Polarity;
+
+public class TypeCheckingOld {
+ public static final boolean PRINT_VALUES = false;
+
+ ErrorLog errorLog;
+ Environment environment;
+ ConcreteModule module;
+
+ ConstraintEnvironment ce;
+ ArrayList<SCLValue[]> valuesWithoutTypeAnnotation = new ArrayList<SCLValue[]>();
+ ArrayList<SCLValue> valuesWithTypeAnnotation = new ArrayList<SCLValue>();
+
+ public TypeCheckingOld(ErrorLog errorLog, Environment environment,
+ ConcreteModule module) {
+ this.errorLog = errorLog;
+ this.environment = environment;
+ this.module = module;
+ }
+
+ public void typeCheck() {
+ ce = new ConstraintEnvironment(environment);
+ groupValueDefinitionsByDependency();
+ typeCheckValuesWithoutTypeAnnotations();
+ typeCheckValuesWithTypeAnnotations();
+ typeCheckRules();
+ }
+
+ private void groupValueDefinitionsByDependency() {
+ // Collect all untyped names
+ final ArrayList<SCLValue> values = new ArrayList<SCLValue>();
+ for(SCLValue value : module.getValues()) {
+ if(value.getExpression() != null) {
+ if(value.getType() == null)
+ values.add(value);
+ else
+ valuesWithTypeAnnotation.add(value);
+ }
+ }
+
+ // Create inverse
+ final TObjectIntHashMap<Object> allRefs =
+ new TObjectIntHashMap<Object>(values.size()*2, 0.5f, -1);
+ for(int i=0;i<values.size();++i)
+ allRefs.put(values.get(i), i);
+
+ // Create groups
+ new StronglyConnectedComponents(values.size()) {
+
+ TIntHashSet set = new TIntHashSet();
+
+ @Override
+ protected void reportComponent(int[] component) {
+ SCLValue[] valueComponent = new SCLValue[component.length];
+ for(int i=0;i<component.length;++i)
+ valueComponent[i] = values.get(component[i]);
+ valuesWithoutTypeAnnotation.add(valueComponent);
+ }
+
+ @Override
+ protected int[] findDependencies(int u) {
+ Expression expression = values.get(u).getExpression();
+ expression.collectRefs(allRefs, set);
+
+ int[] result = set.toArray();
+ set.clear();
+
+ return result;
+ }
+
+ }.findComponents();
+ }
+
+ private void typeCheckValuesWithoutTypeAnnotations() {
+ for(SCLValue[] group : valuesWithoutTypeAnnotation) {
+ if(PRINT_VALUES) {
+ System.out.println("---------------------------------------------");
+ System.out.print("---");
+ for(SCLValue value : group)
+ System.out.print(" " + value.getName());
+ System.out.println();
+ }
+
+ for(int i=0;i<group.length;++i)
+ group[i].setType(Types.metaVar(Kinds.STAR));
+
+ TypingContext context = new TypingContext(errorLog, environment);
+ context.recursiveValues = new THashSet<SCLValue>();
+ for(SCLValue value : group)
+ context.recursiveValues.add(value);
+
+ @SuppressWarnings("unchecked")
+ ArrayList<EVariable>[] constraintDemands = new ArrayList[group.length];
+
+ @SuppressWarnings("unchecked")
+ ArrayList<EPlaceholder>[] recursiveReferences = new ArrayList[group.length];
+ for(int i=0;i<group.length;++i) {
+ context.recursiveReferences = new ArrayList<EPlaceholder>();
+
+ SCLValue value = group[i];
+ Expression expression = value.getExpression();
+ expression = expression.checkType(context, value.getType());
+ value.setExpression(expression);
+
+ ArrayList<EVariable> constraintDemand = context.getConstraintDemand();
+ if(!constraintDemand.isEmpty()) {
+ constraintDemands[i] = constraintDemand;
+ context.resetConstraintDemand();
+ }
+
+ recursiveReferences[i] = context.recursiveReferences;
+ }
+
+ for(Type type : Types.getTypes(group))
+ type.addPolarity(Polarity.POSITIVE);
+ context.solveSubsumptions(group[0].getExpression().getLocation());
+ ArrayList<Constraint> allUnsolvedConstraints = new ArrayList<Constraint>();
+
+ @SuppressWarnings("unchecked")
+ ArrayList<Variable>[] freeEvidence = new ArrayList[group.length];
+ for(int i=0;i<group.length;++i) {
+ if(constraintDemands[i] != null) {
+ SCLValue value = group[i];
+ Expression expression = value.getExpression();
+
+ ReducedConstraints red = ConstraintSolver.solve(
+ ce, new ArrayList<TPred>(0), constraintDemands[i],
+ true /*!Types.isFunction(expression.getType())*/);
+
+ expression = ExpressionAugmentation.augmentSolved(
+ red.solvedConstraints,
+ expression);
+ value.setExpression(expression);
+ value.setType(expression.getType());
+
+ for(Constraint c : red.unsolvedConstraints)
+ if(c.constraint.isGround()) {
+ errorLog.log(c.getDemandLocation(), "There is no instance for <"+c.constraint+">.");
+ }
+
+ ArrayList<Variable> fe = new ArrayList<Variable>(red.unsolvedConstraints.size());
+ for(Constraint c : red.unsolvedConstraints) {
+ allUnsolvedConstraints.add(c);
+ fe.add(c.evidence);
+ }
+ freeEvidence[i] = fe;
+ }
+ else {
+ group[i].setExpression(group[i].getExpression().decomposeMatching());
+ freeEvidence[i] = new ArrayList<Variable>(0);
+ }
+ }
+
+ THashSet<TVar> varSet = new THashSet<TVar>();
+ for(int i=0;i<group.length;++i) {
+ SCLValue value = group[i];
+ Type type = value.getType();
+ type = type.convertMetaVarsToVars();
+ value.setType(type);
+ varSet.addAll(Types.freeVars(type));
+ }
+
+ TVar[] vars = varSet.toArray(new TVar[varSet.size()]);
+
+ // Collect all constraints needed in the group
+ THashSet<TPred> constraintSet = new THashSet<TPred>();
+ for(int i=0;i<group.length;++i) {
+ for(Variable evidence : freeEvidence[i]) {
+ constraintSet.add((TPred)evidence.getType());
+ }
+ }
+ TPred[] constraints = constraintSet.toArray(new TPred[constraintSet.size()]);
+ for(TPred constraint : constraints)
+ if(constraint.containsMetaVars()) {
+ for(Constraint c : allUnsolvedConstraints) {
+ if(Types.equals(c.constraint, constraint)) {
+ errorLog.log(c.getDemandLocation(),
+ "Constrain " + constraint +
+ " contains free variables not mentioned in the type of the value.");
+ break;
+ }
+ }
+ }
+
+
+ // TODO copy to TypeChecking2 from this onwards
+ for(int i=0;i<group.length;++i) {
+ // Create evidence array of every value in the group that has the variables
+ // in the same array as in the shared array
+ ArrayList<Variable> fe = freeEvidence[i];
+ THashMap<TPred, Variable> indexedEvidence = new THashMap<TPred, Variable>(fe.size());
+ for(Variable v : fe)
+ indexedEvidence.put((TPred)v.getType(), v);
+ fe.clear();
+ for(TPred c : constraints) {
+ Variable var = indexedEvidence.get(c);
+ if(var == null) {
+ // These are variables that are not directly needed in
+ // this definition but in the definitions that are
+ // recursively called
+ var = new Variable("evX");
+ var.setType(c);
+ fe.add(var);
+ }
+ fe.add(var);
+ }
+
+ // Add evidence parameters to the functions
+ SCLValue value = group[i];
+ value.setExpression(lambda(Types.NO_EFFECTS, fe, value.getExpression())
+ .closure(vars));
+ value.setType(Types.forAll(vars,
+ Types.constrained(constraints, value.getType())));
+
+ // Add evidence parameters to recursive calls
+ for(EPlaceholder ref : recursiveReferences[i]) {
+ ref.expression = loc(ref.expression.location, apply(
+ Types.NO_EFFECTS,
+ applyTypes(ref.expression, vars),
+ vars(fe)));
+ }
+ }
+ }
+ }
+
+ private void typeCheckValuesWithTypeAnnotations() {
+ ArrayList<TPred> givenConstraints = new ArrayList<TPred>();
+ for(SCLValue value : valuesWithTypeAnnotation) {
+ Type type = value.getType();
+ if(type != null) {
+ if(PRINT_VALUES) {
+ System.out.println("---------------------------------------------");
+ System.out.println("--- " + value.getName() + " :: " + type);
+ }
+ Expression expression = value.getExpression();
+ ArrayList<TVar> vars = new ArrayList<TVar>();
+ type = Types.removeForAll(type, vars);
+ type = Types.removePred(type, givenConstraints);
+
+ /*System.out.println("---------------------------------------------");
+ TypeUnparsingContext tuc = new TypeUnparsingContext();
+ System.out.println("--- " + value.getName() + " :: " + type.toString(tuc));
+ for(TPred t : givenConstraints)
+ System.out.println(">>> " + t.toString(tuc));
+ */
+ TypingContext context = new TypingContext(errorLog, environment);
+ //System.out.println(expression);
+ expression = expression.checkType(context, type);
+ //System.out.println(expression);
+ expression.getType().addPolarity(Polarity.POSITIVE);
+ context.solveSubsumptions(expression.getLocation());
+ ArrayList<EVariable> demands = context.getConstraintDemand();
+ if(!demands.isEmpty() || !givenConstraints.isEmpty()) {
+ ReducedConstraints red =
+ ConstraintSolver.solve(ce, givenConstraints, demands, true);
+ givenConstraints.clear();
+ for(Constraint c : red.unsolvedConstraints) {
+ errorLog.log(c.getDemandLocation(),
+ "Constraint <"+c.constraint+"> is not given and cannot be derived.");
+ }
+ if(errorLog.isEmpty()) { // To prevent exceptions
+ expression = ExpressionAugmentation.augmentSolved(
+ red.solvedConstraints,
+ expression);
+ expression = ExpressionAugmentation.augmentUnsolved(
+ red.givenConstraints,
+ expression);
+ }
+ }
+ else {
+ if(errorLog.isEmpty()) // To prevent exceptions
+ expression = expression.decomposeMatching();
+ }
+ expression = expression.closure(vars.toArray(new TVar[vars.size()]));
+ value.setExpression(expression);
+ }
+ }
+ }
+
+ public void typeCheckRules() {
+ TypingContext context = new TypingContext(errorLog, environment);
+ for(TransformationRule rule : module.getRules()) {
+ context.pushEffectUpperBound(rule.location, Types.metaVar(Kinds.EFFECT));
+ rule.checkType(context);
+ rule.setEffect(Types.canonical(context.popEffectUpperBound()));
+ }
+ context.solveSubsumptions(Locations.NO_LOCATION);
+
+ ArrayList<EVariable> demands = context.getConstraintDemand();
+ if(!demands.isEmpty()) {
+ ReducedConstraints red =
+ ConstraintSolver.solve(ce, new ArrayList<TPred>(), demands, true);
+ for(Constraint c : red.unsolvedConstraints) {
+ errorLog.log(c.getDemandLocation(),
+ "Constraint <"+c.constraint+"> is not given and cannot be derived.");
+ }
+ }
+
+ for(MappingRelation mappingRelation : module.getMappingRelations())
+ for(Type parameterType : mappingRelation.parameterTypes)
+ if(!parameterType.isGround()) {
+ errorLog.log(mappingRelation.location, "Parameter types of the mapping relation are not completely determined.");
+ break;
+ }
+
+ /*for(Rule rule : module.getRules()) {
+ System.out.println(rule.name);
+ for(Variable variable : rule.variables)
+ System.out.println(" " + variable.getName() + " :: " + variable.getType());
+ }*/
+ }
+}