/* * Copyright 2003-2011 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jetbrains.mps.typesystem.inference; import gnu.trove.THashSet; import jetbrains.mps.lang.pattern.util.MatchingUtil; import jetbrains.mps.lang.typesystem.runtime.HUtil; import jetbrains.mps.newTypesystem.SubTypingManagerNew; import jetbrains.mps.newTypesystem.SubtypingUtil; import jetbrains.mps.newTypesystem.state.Equations; import jetbrains.mps.newTypesystem.state.State; import jetbrains.mps.smodel.StaticReference; import org.jetbrains.mps.openapi.model.SNode; import org.jetbrains.mps.openapi.model.SReference; import java.util.*; public class InequalitySystem { private SNode myHoleType; private State myState; public InequalitySystem(SNode holeType, State state) { myHoleType = holeType; myState = state; } public SNode getHoleType() { return myHoleType; } private Set<SNode> myEquals = new THashSet<SNode>(); private Set<SNode> mySubTypes = new THashSet<SNode>(); private Set<SNode> myStrongSubTypes = new THashSet<SNode>(); private Set<SNode> mySuperTypes = new THashSet<SNode>(); private Set<SNode> myStrongSuperTypes = new THashSet<SNode>(); private Set<SNode> myComparableTypes = new THashSet<SNode>(); private Set<SNode> myStrongComparableTypes = new THashSet<SNode>(); public void addEquation(SNode equalWrapper) { myEquals.add(equalWrapper); } public void addSupertype(SNode supertype, boolean isWeak) { if (isWeak) { mySuperTypes.add(supertype); } else { myStrongSuperTypes.add(supertype); } } public void addSubtype(SNode subtype, boolean isWeak) { if (isWeak) { mySubTypes.add(subtype); } else { myStrongSubTypes.add(subtype); } } public void addComparable(SNode comparable, boolean isWeak) { if (isWeak) { myComparableTypes.add(comparable); } else { myStrongComparableTypes.add(comparable); } } public boolean satisfies(SNode type) { SubtypingManager subtypingManager = TypeChecker.getInstance().getSubtypingManager(); for (SNode w : myEquals) { if (!HUtil.isRuntimeHoleType(w) && !MatchingUtil.matchNodes(w, type)) { return false; } } for (SNode supertype : mySuperTypes) { if (!subtypingManager.isSubtype(type, supertype, true)) return false; } for (SNode supertype : myStrongSuperTypes) { if (!subtypingManager.isSubtype(type, supertype, false)) return false; } for (SNode subtype : mySubTypes) { if (!subtypingManager.isSubtype(subtype, type, true)) return false; } for (SNode subtype : myStrongSubTypes) { if (!subtypingManager.isSubtype(subtype, type, false)) return false; } for (SNode comparable : myComparableTypes) { if (!subtypingManager.isComparable(comparable, type, true)) return false; } for (SNode comparable : myStrongComparableTypes) { if (!subtypingManager.isComparable(comparable, type, false)) return false; } return true; } private Set<SNode> expandSet(Set<SNode> set, Equations equations) { if (set.isEmpty()) return set; Set<SNode> result = new HashSet<SNode>(); for (SNode node : set) { SNode expanded = equations.expandNode(node, true); //if (!TypesUtil.isVariable(expanded)) { result.add(expanded); //} } return result; } public void expandAll(Equations equations) { myEquals = expandSet(myEquals, equations); mySubTypes = expandSet(mySubTypes, equations); myComparableTypes = expandSet(myComparableTypes, equations); mySuperTypes = expandSet(mySuperTypes, equations); myStrongSubTypes = expandSet(myStrongSubTypes, equations); myStrongSuperTypes = expandSet(myStrongSuperTypes, equations); myStrongComparableTypes = expandSet(myStrongComparableTypes, equations); } public boolean isEmpty() { return myEquals.isEmpty() && mySubTypes.isEmpty() && mySuperTypes.isEmpty() && myStrongSubTypes.isEmpty() && myStrongSuperTypes.isEmpty() && myComparableTypes.isEmpty() && myStrongComparableTypes.isEmpty(); } public String[] getPresentation() { if (isEmpty()) { return new String[]{"empty"}; } String[] result = new String[myEquals.size() + mySubTypes.size() + mySuperTypes.size() + myStrongSubTypes.size() + myStrongSuperTypes.size()]; int i = 0; for (SNode wrapper : myEquals) { result[i++] = "* == " + wrapper.toString(); } for (SNode wrapper : mySubTypes) { result[i++] = wrapper.toString() + " < *"; } for (SNode wrapper : myStrongSubTypes) { result[i++] = wrapper.toString() + " << *"; } for (SNode wrapper : mySuperTypes) { result[i++] = "* < " + wrapper.toString(); } for (SNode wrapper : myStrongSuperTypes) { result[i++] = "* << " + wrapper.toString(); } for (SNode wrapper : myComparableTypes) { result[i++] = " ~ " + wrapper.toString(); } for (SNode wrapper : myStrongComparableTypes) { result[i++] = " *~ " + wrapper.toString(); } return result; } public SNode getExpectedType() { if (isEmpty()) return null; SubTypingManagerNew subtypingManager = (SubTypingManagerNew) TypeChecker.getInstance().getSubtypingManager(); List<SNode> superTypes = new LinkedList<SNode>(); expandAll(myState.getEquations()); superTypes.addAll(mySuperTypes); superTypes.addAll(myStrongSuperTypes); if (superTypes.isEmpty()) { superTypes.addAll(myComparableTypes); superTypes.addAll(myStrongComparableTypes); } return SubtypingUtil.createLeastCommonSupertype(superTypes, myState.getTypeCheckingContext()); } public void replaceRefs(Map<SNode, SNode> mapping) { Map<SNode, SNode> back = new HashMap<SNode, SNode>(); for (SNode key : mapping.keySet()) { back.put(mapping.get(key), key); } replaceRefs(mySuperTypes, back); replaceRefs(myStrongSuperTypes, back); replaceRefs(mySubTypes, back); replaceRefs(myStrongSubTypes, back); replaceRefs(myComparableTypes, back); replaceRefs(myStrongComparableTypes, back); replaceRefs(myEquals, back); } private void replaceRefs(Set<SNode> nodes, Map<SNode, SNode> mapping) { for (SNode node : nodes) { for (SReference ref : node.getReferences()) { SNode target = jetbrains.mps.util.SNodeOperations.getTargetNodeSilently(ref); SNode restored = mapping.get(target); if (restored != null) { node.setReference(ref.getRole(), new StaticReference(ref.getRole(), ref.getSourceNode(), restored)); } } } } }