/* * 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.newTypesystem.state.blocks; import gnu.trove.THashSet; import jetbrains.mps.lang.typesystem.runtime.AbstractInequationReplacementRule_Runtime; import jetbrains.mps.lang.typesystem.runtime.InequationReplacementRule_Runtime; import jetbrains.mps.lang.typesystem.runtime.IsApplicable2Status; import jetbrains.mps.newTypesystem.SubTypingManagerNew; import jetbrains.mps.newTypesystem.SubtypingResolver; import jetbrains.mps.newTypesystem.TypesUtil; import jetbrains.mps.newTypesystem.operation.AddRemarkOperation; import jetbrains.mps.newTypesystem.operation.CheckSubTypeOperation; import jetbrains.mps.newTypesystem.operation.ProcessReplacementRuleOperation; import jetbrains.mps.languageScope.LanguageScopeExecutor; import jetbrains.mps.newTypesystem.state.Equations; import jetbrains.mps.newTypesystem.state.State; import org.jetbrains.mps.openapi.model.SNode; import jetbrains.mps.typesystem.inference.EquationInfo; import jetbrains.mps.typesystem.inference.TypeChecker; import jetbrains.mps.typesystemEngine.util.LatticeUtil; import jetbrains.mps.util.CollectionUtil; import jetbrains.mps.util.Computable; import jetbrains.mps.util.Pair; import java.util.LinkedList; import java.util.List; import java.util.Set; public class InequalityBlock extends RelationBlock { private boolean lessThan; public SNode getOutput() { if (lessThan) { return myLeftNode; } else { return myRightNode; } } public SNode getInput() { if (isCheckOnly()) { return null; } if (lessThan) { return myRightNode; } else { return myLeftNode; } } @Override public List<Pair<SNode, SNode>> getInputsAndOutputs() { List<Pair<SNode, SNode>> result = new LinkedList<Pair<SNode, SNode>>(); result.add(new Pair<SNode, SNode>(getInput(), getOutput())); return result; } public InequalityBlock(State state, SNode left, SNode right, boolean lessThen, RelationKind kind, EquationInfo equationInfo) { super(state, left, right, kind, equationInfo); this.lessThan = lessThen; } @Override public void performAction() { SNode left = getResolvedInput(myLeftNode); SNode right = getResolvedInput(myRightNode); processInequality(left, right); } private boolean processReplacementRules(final SNode subType, final SNode superType) { final TypeChecker typeChecker = TypeChecker.getInstance(); List<Pair<InequationReplacementRule_Runtime, IsApplicable2Status>> replacementRules = LanguageScopeExecutor.execWithMultiLanguageScope( SubTypingManagerNew.collectLanguagesRecursively(subType, superType), new Computable<List<Pair<InequationReplacementRule_Runtime, IsApplicable2Status>>>() { @Override public List<Pair<InequationReplacementRule_Runtime, IsApplicable2Status>> compute() { return typeChecker.getRulesManager().getReplacementRules(subType, superType); } }); for (jetbrains.mps.util.Pair<InequationReplacementRule_Runtime, IsApplicable2Status> inequalityReplacementRule : replacementRules) { final InequationReplacementRule_Runtime rule = inequalityReplacementRule.o1; final IsApplicable2Status status = inequalityReplacementRule.o2; getState().executeOperation(new ProcessReplacementRuleOperation(subType, superType, new Runnable() { @Override public void run() { ((AbstractInequationReplacementRule_Runtime) rule).processInequation(subType, superType, myEquationInfo, getState().getTypeCheckingContext(), status, myRelationKind.isWeak(), lessThan); } })); return true; } return false; } private void processInequality(final SNode subType, final SNode superType) { if (subType == null || superType == null || subType == superType) { return; } if (!TypesUtil.hasVariablesInside(subType) && !TypesUtil.hasVariablesInside(superType)){ //no need to check if we don't need error reporting if (getState().getTypeCheckingContext().isSingleTypeComputation()) return; if (TypesUtil.match(subType, superType)) { getState().executeOperation(new AddRemarkOperation("Matched: " + subType + " and " + superType)); return; } } if (processReplacementRules(subType, superType)) { return; } final SubTypingManagerNew subTyping = (SubTypingManagerNew) TypeChecker.getInstance().getSubtypingManager(); getState().executeOperation(new CheckSubTypeOperation(subType, superType, new Runnable() { @Override public void run() { if (!calcIsSubtype(subTyping, subType, superType)) { getState().getNodeMaps().reportSubTypeError(subType, superType, myEquationInfo, myRelationKind.isWeak()); } } })); } private boolean calcIsSubtype(SubTypingManagerNew subTyping, SNode subType, SNode superType) { THashSet<Pair<SNode, SNode>> matchingPairs = new THashSet<Pair<SNode, SNode>>(); SubtypingResolver subtypingResolver = new SubtypingResolver(myRelationKind.isWeak(), getState().getTypeCheckingContext(), matchingPairs); boolean result = subtypingResolver.calcIsSubType(subType, superType); if (result) { Equations equations = getState().getEquations(); if (equations != null) { equations.addEquations(matchingPairs, myEquationInfo); } } return result; } @Override public Set<Pair<SNode, ConditionKind>> getInitialInputs() { if (isCheckOnly()) { return CollectionUtil.set(new Pair<SNode, ConditionKind>(myLeftNode, ConditionKind.CONCRETE), new Pair<SNode, ConditionKind>(myRightNode, ConditionKind.CONCRETE)); } else { //hack ConditionKind left = ConditionKind.SHALLOW; if (LatticeUtil.isPolymorphic(myLeftNode)) { left = ConditionKind.CONCRETE; } ConditionKind right = ConditionKind.SHALLOW; if (LatticeUtil.isPolymorphic(myRightNode)) { right = ConditionKind.CONCRETE; } return CollectionUtil.set(new Pair<SNode, ConditionKind>(myLeftNode, left), new Pair<SNode, ConditionKind>(myRightNode, right)); } } @Override public BlockKind getBlockKind() { return BlockKind.INEQUALITY; } private String getPresentationInternal(SNode left, SNode right) { if (lessThan) { return left + myRelationKind.getRelationSign() + right; } else { return right + myRelationKind.getReversedRelationSign() + left; } } @Override public String getShortPresentation() { return getPresentationInternal(myLeftNode, myRightNode); } @Override public String getExpandedPresentation(State state) { return getPresentationInternal(state.expand(myLeftNode), state.expand(myRightNode)); } }