--- /dev/null
+package org.simantics.scl.compiler.elaboration.expressions;
+
+import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;
+import org.simantics.scl.compiler.elaboration.contexts.SimplificationContext;
+import org.simantics.scl.compiler.elaboration.contexts.TranslationContext;
+import org.simantics.scl.compiler.elaboration.contexts.TypingContext;
+import org.simantics.scl.compiler.errors.ErrorLog;
+import org.simantics.scl.compiler.errors.Locations;
+import org.simantics.scl.compiler.internal.elaboration.utils.ExpressionDecorator;
+import org.simantics.scl.compiler.types.Skeletons;
+import org.simantics.scl.compiler.types.TMetaVar;
+import org.simantics.scl.compiler.types.Type;
+import org.simantics.scl.compiler.types.Types;
+import org.simantics.scl.compiler.types.exceptions.MatchException;
+import org.simantics.scl.compiler.types.exceptions.UnificationException;
+import org.simantics.scl.compiler.types.util.TypeListener;
+import org.simantics.scl.compiler.types.util.TypeUnparsingContext;
+
+import gnu.trove.map.hash.THashMap;
+import gnu.trove.map.hash.TObjectIntHashMap;
+import gnu.trove.set.hash.THashSet;
+import gnu.trove.set.hash.TIntHashSet;
+
+public class EAmbiguous extends SimplifiableExpression {
+ public static final boolean DEBUG = false;
+
+ Alternative[] alternatives;
+ boolean[] active;
+ int activeCount;
+ transient TypingContext context;
+ Expression resolvedExpression;
+
+ public abstract static class Alternative {
+ public abstract Type getType();
+ public abstract Expression realize();
+ }
+
+ public EAmbiguous(Alternative[] alternatives) {
+ this.alternatives = alternatives;
+ this.active = new boolean[alternatives.length];
+ for(int i=0;i<alternatives.length;++i)
+ this.active[i] = true;
+ this.activeCount = alternatives.length;
+ }
+
+ @Override
+ public void collectRefs(TObjectIntHashMap<Object> allRefs,
+ TIntHashSet refs) {
+ }
+
+ @Override
+ public void collectVars(TObjectIntHashMap<Variable> allVars,
+ TIntHashSet vars) {
+ }
+
+ @Override
+ public void forVariables(VariableProcedure procedure) {
+ }
+
+ @Override
+ protected void updateType() throws MatchException {
+ throw new InternalCompilerError();
+ }
+
+ private Type getCommonSkeleton() {
+ Type[] types = new Type[activeCount];
+ for(int i=0,j=0;i<alternatives.length;++i)
+ if(active[i])
+ types[j++] = Types.instantiateAndStrip(alternatives[i].getType());
+ return Skeletons.commonSkeleton(context.getEnvironment(), types);
+ }
+
+ private void filterActive() {
+ THashMap<TMetaVar,Type> unifications = new THashMap<TMetaVar,Type>();
+ Type requiredType = getType();
+ if(DEBUG)
+ System.out.println("EAmbigious.filterActive with " + requiredType);
+ for(int i=0;i<alternatives.length;++i)
+ if(active[i]) {
+ unifications.clear();
+ Type alternativeType = Types.instantiateAndStrip(alternatives[i].getType());
+ if(DEBUG)
+ System.out.println(" " + alternativeType);
+ if(!Skeletons.areSkeletonsCompatible(unifications, alternativeType, requiredType)) {
+ active[i] = false;
+ --activeCount;
+ }
+ }
+ if(DEBUG)
+ System.out.println(" activeCount = " + activeCount);
+ }
+
+ private String getNoMatchDescription(Type requiredType) {
+ StringBuilder b = new StringBuilder();
+ b.append("Expected <");
+ requiredType.toString(new TypeUnparsingContext(), b);
+ b.append(">, but no alteratives match the type: ");
+ for(int i=0;i<alternatives.length;++i) {
+ b.append("\n ");
+ b.append(alternatives[i]);
+ b.append(" :: ");
+ alternatives[i].getType().toString(new TypeUnparsingContext(), b);
+ }
+ b.append('.');
+ return b.toString();
+ }
+
+ private String getAmbiguousDescription(Type requiredType) {
+ StringBuilder b = new StringBuilder();
+ b.append("Expected <");
+ requiredType.toString(new TypeUnparsingContext(), b);
+ b.append(">, but multiple values match the type: ");
+ for(int i=0;i<alternatives.length;++i) {
+ b.append("\n ");
+ b.append(alternatives[i]);
+ b.append(" :: ");
+ alternatives[i].getType().toString(new TypeUnparsingContext(), b);
+ }
+ b.append('.');
+ return b.toString();
+ }
+
+
+ private void resolveTo(int i) {
+ if(DEBUG)
+ System.out.println("EAmbigious.resolve to " + alternatives[i]);
+ resolvedExpression = context.instantiate(alternatives[i].realize());
+ Type requiredType = getType();
+ try {
+ Types.unify(resolvedExpression.getType(), requiredType);
+ } catch (UnificationException e) {
+ context.getErrorLog().log(location, getNoMatchDescription(requiredType));
+ }
+ }
+
+ private void listenType() {
+ if(DEBUG)
+ System.out.println("EAmbigious.listenType " + getType());
+ new TypeListener() {
+ @Override
+ public void notifyAboutChange() {
+ if(DEBUG)
+ System.out.println("EAmbigious.notifyAboutChange " + getType());
+ Type requiredType = getType();
+ filterActive();
+ if(activeCount == 0) {
+ context.getErrorLog().log(location, getNoMatchDescription(requiredType));
+ return;
+ }
+ else if(activeCount == 1) {
+ for(int i=0;i<alternatives.length;++i)
+ if(active[i]) {
+ resolveTo(i);
+ return;
+ }
+ }
+ Type commonType = getCommonSkeleton();
+ try {
+ Skeletons.unifySkeletons(requiredType, commonType);
+ listenType();
+ } catch (UnificationException e) {
+ context.getErrorLog().log(location, getNoMatchDescription(requiredType));
+ }
+ }
+ }.listenSkeleton(getType());
+ }
+
+ @Override
+ public Expression inferType(TypingContext context) {
+ this.context = context;
+ context.overloadedExpressions.add(this);
+ setType(getCommonSkeleton());
+ listenType();
+ return this;
+ }
+
+ @Override
+ public void collectFreeVariables(THashSet<Variable> vars) {
+ }
+
+ @Override
+ public Expression resolve(TranslationContext context) {
+ throw new InternalCompilerError("EAmbiguousConstant should not exist in resolve phase.");
+ }
+
+ @Override
+ public void setLocationDeep(long loc) {
+ if(location == Locations.NO_LOCATION)
+ location = loc;
+ }
+
+ @Override
+ public Expression decorate(ExpressionDecorator decorator) {
+ return this;
+ }
+
+ @Override
+ public void collectEffects(THashSet<Type> effects) {
+ // TODO Auto-generated method stub
+ }
+
+ @Override
+ public void accept(ExpressionVisitor visitor) {
+ // TODO Auto-generated method stub
+ }
+
+ @Override
+ public Expression simplify(SimplificationContext context) {
+ if(resolvedExpression != null)
+ return resolvedExpression;
+ else {
+ context.getErrorLog().log(location, getAmbiguousDescription(getType()));
+ return this;
+ }
+ }
+
+ public void assertResolved(ErrorLog errorLog) {
+ if(resolvedExpression == null)
+ errorLog.log(location, getAmbiguousDescription(getType()));
+ }
+
+ @Override
+ public Expression accept(ExpressionTransformer transformer) {
+ return transformer.transform(this);
+ }
+
+}