Home | History | Annotate | Download | only in logic
      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