1 package org.simantics.scl.compiler.compilation;
3 import static org.simantics.scl.compiler.elaboration.expressions.Expressions.apply;
4 import static org.simantics.scl.compiler.elaboration.expressions.Expressions.applyTypes;
5 import static org.simantics.scl.compiler.elaboration.expressions.Expressions.lambda;
6 import static org.simantics.scl.compiler.elaboration.expressions.Expressions.loc;
7 import static org.simantics.scl.compiler.elaboration.expressions.Expressions.vars;
8 import gnu.trove.map.hash.THashMap;
9 import gnu.trove.map.hash.TObjectIntHashMap;
10 import gnu.trove.set.hash.THashSet;
11 import gnu.trove.set.hash.TIntHashSet;
13 import java.util.ArrayList;
14 import java.util.Collection;
15 import java.util.Collections;
17 import org.simantics.scl.compiler.elaboration.contexts.TypingContext;
18 import org.simantics.scl.compiler.elaboration.expressions.EPlaceholder;
19 import org.simantics.scl.compiler.elaboration.expressions.ETransformation;
20 import org.simantics.scl.compiler.elaboration.expressions.EVariable;
21 import org.simantics.scl.compiler.elaboration.expressions.Expression;
22 import org.simantics.scl.compiler.elaboration.expressions.Variable;
23 import org.simantics.scl.compiler.elaboration.modules.SCLValue;
24 import org.simantics.scl.compiler.elaboration.query.Query;
25 import org.simantics.scl.compiler.elaboration.relations.ConcreteRelation;
26 import org.simantics.scl.compiler.elaboration.relations.ConcreteRelation.QuerySection;
27 import org.simantics.scl.compiler.elaboration.relations.SCLRelation;
28 import org.simantics.scl.compiler.elaboration.rules.MappingRelation;
29 import org.simantics.scl.compiler.elaboration.rules.TransformationRule;
30 import org.simantics.scl.compiler.environment.Environment;
31 import org.simantics.scl.compiler.errors.ErrorLog;
32 import org.simantics.scl.compiler.internal.elaboration.constraints.Constraint;
33 import org.simantics.scl.compiler.internal.elaboration.constraints.ConstraintEnvironment;
34 import org.simantics.scl.compiler.internal.elaboration.constraints.ConstraintSolver;
35 import org.simantics.scl.compiler.internal.elaboration.constraints.ExpressionAugmentation;
36 import org.simantics.scl.compiler.internal.elaboration.constraints.ReducedConstraints;
37 import org.simantics.scl.compiler.module.ConcreteModule;
38 import org.simantics.scl.compiler.types.TPred;
39 import org.simantics.scl.compiler.types.TVar;
40 import org.simantics.scl.compiler.types.Type;
41 import org.simantics.scl.compiler.types.Types;
42 import org.simantics.scl.compiler.types.kinds.Kinds;
43 import org.simantics.scl.compiler.types.util.Polarity;
45 public class TypeChecking {
46 final ErrorLog errorLog;
47 final Environment environment;
48 final ConcreteModule module;
50 ConstraintEnvironment ce;
51 TypeCheckingScheduler scheduler;
53 public TypeChecking(ErrorLog errorLog, Environment environment,
54 ConcreteModule module) {
55 this.errorLog = errorLog;
56 this.environment = environment;
60 private void typeCheckValues() {
61 for(final SCLValue value : module.getValues()) {
62 if(value.getExpression() != null) {
63 if(value.getType() == null)
64 scheduler.addTypeInferableDefinition(new TypeInferableDefinition() {
65 ArrayList<EPlaceholder> recursiveReferences;
66 ArrayList<EVariable> constraintDemand;
67 ArrayList<Variable> freeEvidence;
68 ArrayList<Constraint> unsolvedConstraints;
71 public long getLocation() {
72 return value.getExpression().getLocation();
76 public Collection<Object> getDefinedObjects() {
77 return Collections.<Object>singleton(value);
81 public void collectRefs(TObjectIntHashMap<Object> allRefs, TIntHashSet refs) {
82 value.getExpression().collectRefs(allRefs, refs);
86 public void initializeTypeChecking(TypingContext context) {
87 value.setType(Types.metaVar(Kinds.STAR));
88 context.recursiveValues.add(value);
92 public void checkType(TypingContext context) {
93 context.recursiveReferences =
94 this.recursiveReferences = new ArrayList<EPlaceholder>();
96 Expression expression = value.getExpression();
97 context.pushEffectUpperBound(expression.location, Types.PROC);
98 expression = expression.checkType(context, value.getType());
99 context.popEffectUpperBound();
100 value.setExpression(expression);
102 ArrayList<EVariable> constraintDemand = context.getConstraintDemand();
103 if(!constraintDemand.isEmpty()) {
104 this.constraintDemand = constraintDemand;
105 context.resetConstraintDemand();
108 expression.getType().addPolarity(Polarity.POSITIVE);
112 public void solveConstraints() {
113 if(constraintDemand != null) {
114 Expression expression = value.getExpression();
116 ReducedConstraints red = ConstraintSolver.solve(
117 ce, new ArrayList<TPred>(0), constraintDemand,
120 expression = ExpressionAugmentation.augmentSolved(
121 red.solvedConstraints,
123 value.setExpression(expression);
124 value.setType(expression.getType());
126 for(Constraint c : red.unsolvedConstraints)
127 if(c.constraint.isGround())
128 errorLog.log(c.getDemandLocation(), "There is no instance for <"+c.constraint+">.");
130 ArrayList<Variable> fe = new ArrayList<Variable>(red.unsolvedConstraints.size());
131 for(Constraint c : red.unsolvedConstraints)
133 unsolvedConstraints = red.unsolvedConstraints;
137 value.setExpression(value.getExpression().decomposeMatching());
138 freeEvidence = new ArrayList<Variable>(0);
143 public void collectFreeTypeVariables(
144 THashSet<TVar> varSet) {
145 Type type = value.getType();
146 type = type.convertMetaVarsToVars();
148 varSet.addAll(Types.freeVars(type));
152 public ArrayList<Variable> getFreeEvidence() {
157 public ArrayList<Constraint> getUnsolvedConstraints() {
158 return unsolvedConstraints;
162 public void injectEvidence(TVar[] vars, TPred[] constraints) {
163 // Create evidence array of every value in the group that has the variables
164 // in the same array as in the shared array
165 THashMap<TPred, Variable> indexedEvidence = new THashMap<TPred, Variable>(freeEvidence.size());
166 for(Variable v : freeEvidence)
167 indexedEvidence.put((TPred)v.getType(), v);
168 freeEvidence.clear();
169 for(TPred c : constraints) {
170 Variable var = indexedEvidence.get(c);
172 // These are variables that are not directly needed in
173 // this definition but in the definitions that are
174 // recursively called
175 var = new Variable("evX");
177 freeEvidence.add(var);
179 freeEvidence.add(var);
182 // Add evidence parameters to the functions
183 value.setExpression(lambda(Types.NO_EFFECTS, freeEvidence, value.getExpression())
185 value.setType(Types.forAll(vars,
186 Types.constrained(constraints, value.getType())));
188 // Add evidence parameters to recursive calls
189 for(EPlaceholder ref : recursiveReferences) {
190 ref.expression = loc(ref.expression.location, apply(
192 applyTypes(ref.expression, vars),
193 vars(freeEvidence)));
198 scheduler.addPostTypeCheckingRunnable(new Runnable() {
201 Type type = value.getType();
202 Expression expression = value.getExpression();
205 ArrayList<TVar> vars = new ArrayList<TVar>();
206 type = Types.removeForAll(type, vars);
207 ArrayList<TPred> givenConstraints = new ArrayList<TPred>();
208 type = Types.removePred(type, givenConstraints);
210 TypingContext context = new TypingContext(errorLog, environment);
211 context.pushEffectUpperBound(expression.location, Types.PROC);
212 expression = expression.checkType(context, type);
213 context.popEffectUpperBound();
214 expression.getType().addPolarity(Polarity.POSITIVE);
215 context.solveSubsumptions(expression.getLocation());
216 ArrayList<EVariable> demands = context.getConstraintDemand();
217 if(!demands.isEmpty() || !givenConstraints.isEmpty()) {
218 ReducedConstraints red =
219 ConstraintSolver.solve(ce, givenConstraints, demands, true);
220 givenConstraints.clear();
221 for(Constraint c : red.unsolvedConstraints) {
222 errorLog.log(c.getDemandLocation(),
223 "Constraint <"+c.constraint+"> is not given and cannot be derived.");
225 if(errorLog.isEmpty()) { // To prevent exceptions
226 expression = ExpressionAugmentation.augmentSolved(
227 red.solvedConstraints,
229 expression = ExpressionAugmentation.augmentUnsolved(
230 red.givenConstraints,
235 if(errorLog.isEmpty()) // To prevent exceptions
236 expression = expression.decomposeMatching();
238 expression = expression.closure(vars.toArray(new TVar[vars.size()]));
239 value.setExpression(expression);
240 } catch(Exception e) {
241 errorLog.log(expression.location, e);
249 private void typeCheckRelations() {
250 for(SCLRelation relation_ : module.getRelations()) {
251 if(!(relation_ instanceof ConcreteRelation))
253 final ConcreteRelation relation = (ConcreteRelation)relation_;
254 scheduler.addTypeInferableDefinition(new TypeInferableDefinition() {
257 public void initializeTypeChecking(TypingContext context) {
258 for(Variable parameter : relation.parameters) {
259 Type type = Types.metaVar(Kinds.STAR);
260 type.addPolarity(Polarity.BIPOLAR);
261 parameter.setType(type);
266 public void solveConstraints() {
270 public void injectEvidence(TVar[] vars, TPred[] constraints) {
271 relation.typeVariables = vars;
275 public ArrayList<Constraint> getUnsolvedConstraints() {
276 return new ArrayList<Constraint>(0); // TODO
280 public long getLocation() {
281 return relation.location;
285 public ArrayList<Variable> getFreeEvidence() {
286 return new ArrayList<Variable>(0); // TODO
290 public Collection<Object> getDefinedObjects() {
291 return Collections.<Object>singleton(relation);
295 public void collectRefs(TObjectIntHashMap<Object> allRefs, TIntHashSet refs) {
296 for(QuerySection section : relation.getSections())
297 section.query.collectRefs(allRefs, refs);
301 public void collectFreeTypeVariables(THashSet<TVar> varSet) {
302 for(Variable parameter : relation.parameters) {
303 Type parameterType = parameter.getType().convertMetaVarsToVars();
304 varSet.addAll(Types.freeVars(parameterType));
309 public void checkType(TypingContext context) {
310 for(QuerySection section : relation.getSections()) {
311 section.effect = Types.metaVar(Kinds.EFFECT);
312 context.pushEffectUpperBound(relation.location, section.effect);
313 for(Variable variable : section.existentials)
314 variable.setType(Types.metaVar(Kinds.STAR));
315 section.query.checkType(context);
316 context.popEffectUpperBound();
319 if(relation.enforceSection != null) {
320 relation.writingEffect = Types.metaVar(Kinds.EFFECT);
321 context.pushEffectUpperBound(relation.location, relation.writingEffect);
322 relation.enforceSection.checkType(context);
323 context.popEffectUpperBound();
330 public void typeCheck() {
331 ce = new ConstraintEnvironment(environment);
332 scheduler = new TypeCheckingScheduler(errorLog, environment);
335 typeCheckRelations();
338 scheduler.schedule();
341 private void typeCheckRules() {
342 scheduler.addTypeInferableDefinition(new TypeInferableDefinition() {
344 public void solveConstraints() {
345 // TODO Auto-generated method stub
349 public void injectEvidence(TVar[] vars, TPred[] constraints) {
350 // TODO Auto-generated method stub
355 public void initializeTypeChecking(TypingContext context) {
356 // TODO Auto-generated method stub
361 public ArrayList<Constraint> getUnsolvedConstraints() {
362 return new ArrayList<Constraint>(0);
364 ArrayList<EVariable> demands = context.getConstraintDemand();
365 if(!demands.isEmpty()) {
366 ReducedConstraints red =
367 ConstraintSolver.solve(ce, new ArrayList<TPred>(), demands, true);
368 for(Constraint c : red.unsolvedConstraints) {
369 errorLog.log(c.getDemandLocation(),
370 "Constraint <"+c.constraint+"> is not given and cannot be derived.");
376 public long getLocation() {
377 // TODO Auto-generated method stub
382 public ArrayList<Variable> getFreeEvidence() {
383 return new ArrayList<Variable>(0);
387 public Collection<Object> getDefinedObjects() {
388 return Collections.singleton(ETransformation.TRANSFORMATION_RULES_TYPECHECKED);
392 public void collectRefs(TObjectIntHashMap<Object> allRefs, TIntHashSet refs) {
393 for(TransformationRule rule : module.getRules())
394 for(Query[] queries : rule.sections.values())
395 for(Query query : queries)
396 query.collectRefs(allRefs, refs);
400 public void collectFreeTypeVariables(THashSet<TVar> varSet) {
404 public void checkType(TypingContext context) {
405 for(TransformationRule rule : module.getRules()) {
406 context.pushEffectUpperBound(rule.location, Types.metaVar(Kinds.EFFECT));
407 rule.checkType(context);
408 rule.setEffect(Types.canonical(context.popEffectUpperBound()));
413 if(!module.getMappingRelations().isEmpty())
414 scheduler.addPostTypeCheckingRunnable(new Runnable() {
417 for(MappingRelation mappingRelation : module.getMappingRelations())
418 for(Type parameterType : mappingRelation.parameterTypes)
419 if(!parameterType.isGround()) {
420 errorLog.log(mappingRelation.location, "Parameter types of the mapping relation are not completely determined.");