package jetbrains.mps.baseLanguage.scopes; /*Generated by MPS */ import java.util.List; import org.jetbrains.mps.openapi.model.SNode; import jetbrains.mps.util.Pair; import jetbrains.mps.internal.collections.runtime.ListSequence; import jetbrains.mps.lang.smodel.generator.smodelAdapter.SLinkOperations; import jetbrains.mps.smodel.adapter.structure.MetaAdapterFactory; import jetbrains.mps.lang.smodel.generator.smodelAdapter.SNodeOperations; import java.util.ArrayList; import java.util.Map; import java.util.HashMap; import jetbrains.mps.typesystem.inference.TypeContextManager; import jetbrains.mps.util.Computable; import jetbrains.mps.typesystem.inference.TypeChecker; import org.jetbrains.annotations.Nullable; import jetbrains.mps.typesystem.inference.util.StructuralNodeMap; import java.util.Set; import jetbrains.mps.typesystem.inference.SubtypingManager; import jetbrains.mps.internal.collections.runtime.SetSequence; import java.util.HashSet; import jetbrains.mps.newTypesystem.SubtypingUtil; import org.jetbrains.annotations.NotNull; import jetbrains.mps.internal.collections.runtime.MapSequence; import jetbrains.mps.internal.collections.runtime.IMapping; import java.util.Iterator; import jetbrains.mps.internal.collections.runtime.Sequence; public class MethodResolveUtil { private MethodResolveUtil() { } public static List<SNode> selectByParmCount(List<SNode> methods, List<SNode> actualArgs) { return selectByParmCountReportNoGoodMethodNode(methods, actualArgs).o1; } private static Pair<List<SNode>, Boolean> selectByParmCountReportNoGoodMethodNode(List<SNode> methods, List<SNode> actualArgs) { int minParmCountDiff = Integer.MAX_VALUE; int[] parmCountDiffs = new int[ListSequence.fromList(methods).count()]; boolean[] varargs = new boolean[ListSequence.fromList(methods).count()]; int index = 0; for (SNode method : methods) { int parmCountDiff; int count = ListSequence.fromList(SLinkOperations.getChildren(method, MetaAdapterFactory.getContainmentLink(0xf3061a5392264cc5L, 0xa443f952ceaf5816L, 0xf8cc56b1fcL, 0xf8cc56b1feL, "parameter"))).count(); int actualArgsCount = ListSequence.fromList(actualArgs).count(); boolean vararg = false; if (count > 0 && SNodeOperations.isInstanceOf(SLinkOperations.getTarget(ListSequence.fromList(SLinkOperations.getChildren(method, MetaAdapterFactory.getContainmentLink(0xf3061a5392264cc5L, 0xa443f952ceaf5816L, 0xf8cc56b1fcL, 0xf8cc56b1feL, "parameter"))).last(), MetaAdapterFactory.getContainmentLink(0xf3061a5392264cc5L, 0xa443f952ceaf5816L, 0x450368d90ce15bc3L, 0x4ed4d318133c80ceL, "type")), MetaAdapterFactory.getConcept(0xf3061a5392264cc5L, 0xa443f952ceaf5816L, 0x11c08f42e7bL, "jetbrains.mps.baseLanguage.structure.VariableArityType"))) { vararg = true; parmCountDiff = Math.max(0, (count - 1) - actualArgsCount); } else { parmCountDiff = Math.abs(count - actualArgsCount); } varargs[index] = vararg; parmCountDiffs[index++] = parmCountDiff; minParmCountDiff = Math.min(minParmCountDiff, parmCountDiff); } boolean good = true; List<SNode> result = new ArrayList<SNode>(); for (int i = 0; i < parmCountDiffs.length; i++) { if (minParmCountDiff == parmCountDiffs[i]) { SNode method = ListSequence.fromList(methods).getElement(i); if (varargs[i]) { ListSequence.fromList(result).addElement(method); } else { ListSequence.fromList(result).insertElement(0, method); } if (minParmCountDiff > 0) { good = false; break; } } } return new Pair<List<SNode>, Boolean>(result, good); } public static SNode chooseByParameterType(List<SNode> candidates, List<SNode> actualArgs, Map<SNode, SNode> typeByTypeVar) { return MethodResolveUtil.chooseByParameterTypeReportNoGoodMethodNode(null, candidates, actualArgs, typeByTypeVar).o1; } public static Pair<SNode, Boolean> chooseByParameterTypeReportNoGoodMethodNode(SNode current, List<SNode> candidates, List<SNode> actualArgs, Map<SNode, SNode> typeByTypeVar) { Map<SNode, SNode> nodesAndTypes = new HashMap<SNode, SNode>(); int i = 1; Boolean good = true; for (boolean mostSpecific = false; i <= 2; mostSpecific = !(mostSpecific), i++) { int indexOfArg = 0; for (SNode actualArg : actualArgs) { final SNode term = actualArg; SNode typeOfArg; if (nodesAndTypes.containsKey(term)) { typeOfArg = nodesAndTypes.get(term); } else { typeOfArg = TypeContextManager.getInstance().runResolveAction(new Computable<SNode>() { @Override public SNode compute() { return TypeChecker.getInstance().getTypeOf(term); } }); nodesAndTypes.put(term, typeOfArg); } List<SNode> candidates1 = selectByParameterTypeNode(typeOfArg, indexOfArg, candidates, typeByTypeVar, mostSpecific, false); if (ListSequence.fromList(candidates1).isEmpty()) { candidates1 = selectByParameterTypeNode(typeOfArg, indexOfArg, candidates, typeByTypeVar, mostSpecific, true); } if (candidates1.isEmpty()) { good = false; break; } if (candidates1.size() == 1) { return new Pair<SNode, Boolean>(candidates1.get(0), good); } if (mostSpecific && current != null && ListSequence.fromList(candidates).contains(current)) { return new Pair<SNode, Boolean>(current, good); } candidates = candidates1; indexOfArg++; } } return new Pair<SNode, Boolean>(ListSequence.fromList(candidates).first(), good); } private static List<SNode> selectByParameterTypeNode(@Nullable SNode typeOfArg, int indexOfArg, List<SNode> candidates, Map<SNode, SNode> typeByTypeVar, boolean mostSpecific, boolean isWeak) { List<SNode> result = new ArrayList<SNode>(); StructuralNodeMap<Set<SNode>> typesOfParamToMethods = new StructuralNodeMap<Set<SNode>>(); SubtypingManager subtypingManager = TypeChecker.getInstance().getSubtypingManager(); for (SNode candidate : candidates) { boolean varArg = false; List<SNode> params = SLinkOperations.getChildren(candidate, MetaAdapterFactory.getContainmentLink(0xf3061a5392264cc5L, 0xa443f952ceaf5816L, 0xf8cc56b1fcL, 0xf8cc56b1feL, "parameter")); SNode type = SLinkOperations.getTarget(ListSequence.fromList(params).last(), MetaAdapterFactory.getContainmentLink(0xf3061a5392264cc5L, 0xa443f952ceaf5816L, 0x450368d90ce15bc3L, 0x4ed4d318133c80ceL, "type")); if (SNodeOperations.isInstanceOf(type, MetaAdapterFactory.getConcept(0xf3061a5392264cc5L, 0xa443f952ceaf5816L, 0x11c08f42e7bL, "jetbrains.mps.baseLanguage.structure.VariableArityType"))) { if (ListSequence.fromList(params).count() - 1 <= indexOfArg) { varArg = true; } } else { if (ListSequence.fromList(params).count() <= indexOfArg) { continue; } } Set<SNode> methodTypeVariableDecls = SetSequence.fromSetWithValues(new HashSet<SNode>(), SLinkOperations.getChildren(candidate, MetaAdapterFactory.getContainmentLink(0xf3061a5392264cc5L, 0xa443f952ceaf5816L, 0x102463b447aL, 0x102463bb98eL, "typeVariableDeclaration"))); SNode typeOfParam = (varArg ? SLinkOperations.getTarget(SNodeOperations.cast(type, MetaAdapterFactory.getConcept(0xf3061a5392264cc5L, 0xa443f952ceaf5816L, 0x11c08f42e7bL, "jetbrains.mps.baseLanguage.structure.VariableArityType")), MetaAdapterFactory.getContainmentLink(0xf3061a5392264cc5L, 0xa443f952ceaf5816L, 0x11c08f42e7bL, 0x11c08f5f38cL, "componentType")) : SLinkOperations.getTarget(ListSequence.fromList(params).getElement(indexOfArg), MetaAdapterFactory.getContainmentLink(0xf3061a5392264cc5L, 0xa443f952ceaf5816L, 0x450368d90ce15bc3L, 0x4ed4d318133c80ceL, "type"))); if ((typeOfParam == null)) { continue; } typeOfParam = GenericTypesUtil.getTypeWithResolvedTypeVars(typeOfParam, typeByTypeVar); typeOfParam = GenericTypesUtil.methodParamTypeWoutTypeVars(typeOfParam, methodTypeVariableDecls); if (subtypingManager.isSubtype(typeOfArg, typeOfParam, isWeak)) { Set<SNode> methods = typesOfParamToMethods.get(typeOfParam); if (methods == null) { methods = new HashSet<SNode>(); typesOfParamToMethods.put(typeOfParam, methods); } methods.add(candidate); result.add(candidate); } } if (mostSpecific) { Set<SNode> goodParamTypes = typesOfParamToMethods.keySet(); Set<SNode> mostSpecificTypes = SubtypingUtil.mostSpecificTypes(goodParamTypes); if (!(mostSpecificTypes.isEmpty())) { result = new ArrayList<SNode>(); for (SNode mostSpecificType : mostSpecificTypes) { result.addAll(typesOfParamToMethods.get(mostSpecificType)); } } } return result; } public static Map<SNode, SNode> getTypesByTypeVars(@NotNull SNode classifier, Iterable<SNode> typeParameters) { Map<SNode, SNode> typeByTypeVar = MapSequence.fromMap(new HashMap<SNode, SNode>()); for (IMapping<SNode, SNode> elem : MapSequence.fromMap(ClassifierScopeUtils.resolveClassifierTypeVars(classifier))) { typeByTypeVar.put(elem.key(), elem.value()); } Iterator<SNode> typeParms = Sequence.fromIterable(typeParameters).iterator(); for (SNode typeVar : ListSequence.fromList(SLinkOperations.getChildren(classifier, MetaAdapterFactory.getContainmentLink(0xf3061a5392264cc5L, 0xa443f952ceaf5816L, 0x102463b447aL, 0x102463bb98eL, "typeVariableDeclaration")))) { if (!(typeParms.hasNext())) { break; } SNode typeParm = SNodeOperations.as(typeParms.next(), MetaAdapterFactory.getConcept(0xf3061a5392264cc5L, 0xa443f952ceaf5816L, 0xf8c37f506dL, "jetbrains.mps.baseLanguage.structure.Type")); if ((typeParm == null) || SLinkOperations.getTarget(SNodeOperations.as(typeParm, MetaAdapterFactory.getConcept(0xf3061a5392264cc5L, 0xa443f952ceaf5816L, 0x102467229d8L, "jetbrains.mps.baseLanguage.structure.TypeVariableReference")), MetaAdapterFactory.getReferenceLink(0xf3061a5392264cc5L, 0xa443f952ceaf5816L, 0x102467229d8L, 0x1024673a581L, "typeVariableDeclaration")) == typeVar) { continue; } MapSequence.fromMap(typeByTypeVar).put(typeVar, SNodeOperations.cast(typeParm, MetaAdapterFactory.getConcept(0xf3061a5392264cc5L, 0xa443f952ceaf5816L, 0xf8c37f506dL, "jetbrains.mps.baseLanguage.structure.Type"))); } return typeByTypeVar; } }