1 /* 2 * Copyright 2016 Federico Tomassetti 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.github.javaparser.symbolsolver.logic; 18 19 import com.github.javaparser.resolution.declarations.ResolvedTypeParameterDeclaration; 20 import com.github.javaparser.resolution.types.*; 21 import com.github.javaparser.symbolsolver.model.typesystem.*; 22 23 import java.util.ArrayList; 24 import java.util.HashMap; 25 import java.util.List; 26 import java.util.Map; 27 import java.util.stream.Collectors; 28 29 /** 30 * @author Federico Tomassetti 31 */ 32 public class InferenceContext { 33 34 private int nextInferenceVariableId = 0; 35 private ObjectProvider objectProvider; 36 private List<InferenceVariableType> inferenceVariableTypes = new ArrayList<>(); 37 38 public InferenceContext(ObjectProvider objectProvider) { 39 this.objectProvider = objectProvider; 40 } 41 42 private Map<String, InferenceVariableType> inferenceVariableTypeMap = new HashMap<>(); 43 44 private InferenceVariableType inferenceVariableTypeForTp(ResolvedTypeParameterDeclaration tp) { 45 if (!inferenceVariableTypeMap.containsKey(tp.getName())) { 46 InferenceVariableType inferenceVariableType = new InferenceVariableType(nextInferenceVariableId++, objectProvider); 47 inferenceVariableTypes.add(inferenceVariableType); 48 inferenceVariableType.setCorrespondingTp(tp); 49 inferenceVariableTypeMap.put(tp.getName(), inferenceVariableType); 50 } 51 return inferenceVariableTypeMap.get(tp.getName()); 52 } 53 54 /** 55 * 56 * @return the actual with the inference variable inserted 57 */ 58 public ResolvedType addPair(ResolvedType target, ResolvedType actual) { 59 target = placeInferenceVariables(target); 60 actual = placeInferenceVariables(actual); 61 registerCorrespondance(target, actual); 62 return target; 63 } 64 65 public ResolvedType addSingle(ResolvedType actual) { 66 return placeInferenceVariables(actual); 67 } 68 69 private void registerCorrespondance(ResolvedType formalType, ResolvedType actualType) { 70 if (formalType.isReferenceType() && actualType.isReferenceType()) { 71 ResolvedReferenceType formalTypeAsReference = formalType.asReferenceType(); 72 ResolvedReferenceType actualTypeAsReference = actualType.asReferenceType(); 73 74 if (!formalTypeAsReference.getQualifiedName().equals(actualTypeAsReference.getQualifiedName())) { 75 List<ResolvedReferenceType> ancestors = actualTypeAsReference.getAllAncestors(); 76 final String formalParamTypeQName = formalTypeAsReference.getQualifiedName(); 77 List<ResolvedType> correspondingFormalType = ancestors.stream().filter((a) -> a.getQualifiedName().equals(formalParamTypeQName)).collect(Collectors.toList()); 78 if (correspondingFormalType.isEmpty()) { 79 ancestors = formalTypeAsReference.getAllAncestors(); 80 final String actualParamTypeQname = actualTypeAsReference.getQualifiedName(); 81 List<ResolvedType> correspondingActualType = ancestors.stream().filter(a -> a.getQualifiedName().equals(actualParamTypeQname)).collect(Collectors.toList()); 82 if (correspondingActualType.isEmpty()){ 83 throw new ConfilictingGenericTypesException(formalType, actualType); 84 } 85 correspondingFormalType = correspondingActualType; 86 87 } 88 actualTypeAsReference = correspondingFormalType.get(0).asReferenceType(); 89 } 90 91 if (formalTypeAsReference.getQualifiedName().equals(actualTypeAsReference.getQualifiedName())) { 92 if (!formalTypeAsReference.typeParametersValues().isEmpty()) { 93 if (actualTypeAsReference.isRawType()) { 94 // nothing to do 95 } else { 96 int i = 0; 97 for (ResolvedType formalTypeParameter : formalTypeAsReference.typeParametersValues()) { 98 registerCorrespondance(formalTypeParameter, actualTypeAsReference.typeParametersValues().get(i)); 99 i++; 100 } 101 } 102 } 103 } 104 } else if (formalType instanceof InferenceVariableType && !actualType.isPrimitive()) { 105 ((InferenceVariableType) formalType).registerEquivalentType(actualType); 106 if (actualType instanceof InferenceVariableType) { 107 ((InferenceVariableType) actualType).registerEquivalentType(formalType); 108 } 109 } else if (actualType.isNull()) { 110 // nothing to do 111 } else if (actualType.equals(formalType)) { 112 // nothing to do 113 } else if (actualType.isArray() && formalType.isArray()) { 114 registerCorrespondance(formalType.asArrayType().getComponentType(), actualType.asArrayType().getComponentType()); 115 } else if (formalType.isWildcard()) { 116 // nothing to do 117 if ((actualType instanceof InferenceVariableType) && formalType.asWildcard().isBounded()) { 118 ((InferenceVariableType) actualType).registerEquivalentType(formalType.asWildcard().getBoundedType()); 119 if (formalType.asWildcard().getBoundedType() instanceof InferenceVariableType) { 120 ((InferenceVariableType) formalType.asWildcard().getBoundedType()).registerEquivalentType(actualType); 121 } 122 } 123 if (actualType.isWildcard()) { 124 ResolvedWildcard formalWildcard = formalType.asWildcard(); 125 ResolvedWildcard actualWildcard = actualType.asWildcard(); 126 if (formalWildcard.isBounded() && formalWildcard.getBoundedType() instanceof InferenceVariableType) { 127 if (formalWildcard.isSuper() && actualWildcard.isSuper()) { 128 ((InferenceVariableType) formalType.asWildcard().getBoundedType()).registerEquivalentType(actualWildcard.getBoundedType()); 129 } else if (formalWildcard.isExtends() && actualWildcard.isExtends()) { 130 ((InferenceVariableType) formalType.asWildcard().getBoundedType()).registerEquivalentType(actualWildcard.getBoundedType()); 131 } 132 } 133 } 134 135 if (actualType.isReferenceType()){ 136 if (formalType.asWildcard().isBounded()){ 137 registerCorrespondance(formalType.asWildcard().getBoundedType(), actualType); 138 } 139 } 140 } else if (actualType instanceof InferenceVariableType){ 141 if (formalType instanceof ResolvedReferenceType){ 142 ((InferenceVariableType) actualType).registerEquivalentType(formalType); 143 } else if (formalType instanceof InferenceVariableType){ 144 ((InferenceVariableType) actualType).registerEquivalentType(formalType); 145 } 146 } else if (actualType.isConstraint()){ 147 ResolvedLambdaConstraintType constraintType = actualType.asConstraintType(); 148 if (constraintType.getBound() instanceof InferenceVariableType){ 149 ((InferenceVariableType) constraintType.getBound()).registerEquivalentType(formalType); 150 } 151 } else if (actualType.isPrimitive()) { 152 if (formalType.isPrimitive()) { 153 // nothing to do 154 } else { 155 registerCorrespondance(formalType, objectProvider.byName(actualType.asPrimitive().getBoxTypeQName())); 156 } 157 } else { 158 throw new UnsupportedOperationException(formalType.describe() + " " + actualType.describe()); 159 } 160 } 161 162 private ResolvedType placeInferenceVariables(ResolvedType type) { 163 if (type.isWildcard()) { 164 if (type.asWildcard().isExtends()) { 165 return ResolvedWildcard.extendsBound(placeInferenceVariables(type.asWildcard().getBoundedType())); 166 } else if (type.asWildcard().isSuper()) { 167 return ResolvedWildcard.superBound(placeInferenceVariables(type.asWildcard().getBoundedType())); 168 } else { 169 return type; 170 } 171 } else if (type.isTypeVariable()) { 172 return inferenceVariableTypeForTp(type.asTypeParameter()); 173 } else if (type.isReferenceType()) { 174 return type.asReferenceType().transformTypeParameters(tp -> placeInferenceVariables(tp)); 175 } else if (type.isArray()) { 176 return new ResolvedArrayType(placeInferenceVariables(type.asArrayType().getComponentType())); 177 } else if (type.isNull() || type.isPrimitive() || type.isVoid()) { 178 return type; 179 } else if (type.isConstraint()){ 180 return ResolvedLambdaConstraintType.bound(placeInferenceVariables(type.asConstraintType().getBound())); 181 } else if (type instanceof InferenceVariableType) { 182 return type; 183 } else { 184 throw new UnsupportedOperationException(type.describe()); 185 } 186 } 187 188 public ResolvedType resolve(ResolvedType type) { 189 if (type instanceof InferenceVariableType) { 190 InferenceVariableType inferenceVariableType = (InferenceVariableType) type; 191 return inferenceVariableType.equivalentType(); 192 } else if (type.isReferenceType()) { 193 return type.asReferenceType().transformTypeParameters(tp -> resolve(tp)); 194 } else if (type.isNull() || type.isPrimitive() || type.isVoid()) { 195 return type; 196 } else if (type.isArray()) { 197 return new ResolvedArrayType(resolve(type.asArrayType().getComponentType())); 198 } else if (type.isWildcard()) { 199 if (type.asWildcard().isExtends()) { 200 return ResolvedWildcard.extendsBound(resolve(type.asWildcard().getBoundedType())); 201 } else if (type.asWildcard().isSuper()) { 202 return ResolvedWildcard.superBound(resolve(type.asWildcard().getBoundedType())); 203 } else { 204 return type; 205 } 206 } else { 207 throw new UnsupportedOperationException(type.describe()); 208 } 209 } 210 } 211