public Resolve(Symbols symbols, BytecodeCompleter bytecodeCompleter, ParametrizedTypeCache parametrizedTypeCache) { this.symbols = symbols; this.bytecodeCompleter = bytecodeCompleter; this.typeSubstitutionSolver = new TypeSubstitutionSolver(parametrizedTypeCache, symbols); }
public JavaType resolveTypeSubstitution(JavaType type, JavaType definition) { return typeSubstitutionSolver.applySiteSubstitution(type, definition); } public List<JavaType> resolveTypeSubstitution(List<JavaType> formals, TypeSubstitution substitution) {
private List<JavaType> applySamSubstitution(Type type, List<JavaType> samTypes) { JavaType functionType = (JavaType) type; if(functionType instanceof ParametrizedTypeJavaType) { functionType = typeSubstitutionSolver.functionType((ParametrizedTypeJavaType) functionType); } List<JavaType> argTypes = typeSubstitutionSolver.applySiteSubstitutionToFormalParameters(samTypes, functionType); return argTypes.stream().map(argType -> { if (argType.isTagged(JavaType.WILDCARD)) { // JLS8 9.9 Function types : this is approximated for ? extends X types (cf JLS) return ((WildCardType) argType).bound; } return argType; }).collect(Collectors.toList()); }
public JavaType resolveTypeSubstitutionWithDiamondOperator(ParametrizedTypeJavaType type, JavaType definition) { ParametrizedTypeJavaType result = type; if (definition.isParameterized()) { TypeSubstitution substitution = TypeSubstitutionSolver.substitutionFromSuperType(type, (ParametrizedTypeJavaType) definition); result = (ParametrizedTypeJavaType) typeSubstitutionSolver.applySubstitution(type, substitution); } return typeSubstitutionSolver.erasureSubstitution(result); }
return bestSoFar; TypeSubstitution substitution = typeSubstitutionSolver.getTypeSubstitution(methodJavaSymbol, callSite, typeParams, argTypes); if (substitution == null) { return bestSoFar; formals = typeSubstitutionSolver.applySiteSubstitutionToFormalParameters(formals, callSite); if(defSite != callSite) { formals = typeSubstitutionSolver.applySiteSubstitutionToFormalParameters(formals, defSite); formals = typeSubstitutionSolver.applySubstitutionToFormalParameters(formals, substitution); if (!isArgumentsAcceptable(argTypes, formals, methodJavaSymbol.isVarArgs(), looseInvocation)) { return bestSoFar; thrownTypes = erasure(thrownTypes); } else { returnType = typeSubstitutionSolver.getReturnType(returnType, defSite, callSite, substitution, mostSpecificMethod); thrownTypes = thrownTypes.stream() .map(t -> typeSubstitutionSolver.applySiteSubstitution(t, callSite)) .map(t -> typeSubstitutionSolver.applySubstitution(t, substitution)) .collect(Collectors.toList());
@CheckForNull TypeSubstitution getTypeSubstitution(JavaSymbol.MethodJavaSymbol method, JavaType site, List<JavaType> typeParams, List<JavaType> argTypes) { List<JavaType> formals = ((MethodJavaType) method.type).argTypes; TypeSubstitution substitution = new TypeSubstitution(); if (method.isParametrized() || constructParametrizedTypeWithoutSubstitution(method, site)) { if (!typeParams.isEmpty()) { substitution = getSubstitutionFromTypeParams(method.typeVariableTypes, typeParams); } else if (formals.isEmpty()) { // substitution can not be inferred, as it is not based on arguments, method call is still valid return substitution; } else { formals = applySiteSubstitutionToFormalParameters(formals, site); substitution = typeInferenceSolver.inferTypeSubstitution(method, formals, argTypes); } if (!isValidSubstitution(substitution, site)) { // check for valid substitution in supertypes, null if no valid substitution is found return getTypeSubstitutionFromSuperTypes(method, site, typeParams, argTypes); } } return substitution; }
JavaType getReturnType(@Nullable JavaType returnType, JavaType defSite, JavaType callSite, TypeSubstitution substitution, JavaSymbol.MethodJavaSymbol method) { JavaType resultType = returnType; if (method.isConstructor()) { if (constructParametrizedTypeWithoutSubstitution(method, defSite)) { resultType = applySubstitution(defSite, substitution); } else { return defSite; } } // As per getClass javadoc: // The actual result type [of getClass] is Class<? extends |X|> where |X| is the erasure of the static type of the expression on which getClass is called. if(defSite == symbols.objectType && "getClass".equals(method.name())) { TypeJavaSymbol classSymbol = symbols.classType.symbol; JavaType wildcardType = parametrizedTypeCache.getWildcardType(callSite.erasure(), WildCardType.BoundType.EXTENDS); resultType = parametrizedTypeCache.getParametrizedTypeType(classSymbol, new TypeSubstitution().add(classSymbol.typeVariableTypes.get(0), wildcardType)); } resultType = applySiteSubstitution(resultType, defSite); if (callSite != defSite) { resultType = applySiteSubstitution(resultType, callSite); } resultType = applySubstitution(resultType, substitution); if (!isReturnTypeCompletelySubstituted(resultType, method.typeVariableTypes) || (method.isConstructor() && !isReturnTypeCompletelySubstituted(resultType, defSite.symbol.typeVariableTypes))) { resultType = symbols.deferedType(resultType); } return resultType; }
@Override protected ClassJavaType substitutedType(ClassJavaType type) { return (ClassJavaType) typeSubstitutionSolver.applySubstitution(type, typeSubstitution); } }
@VisibleForTesting List<JavaType> applySiteSubstitutionToFormalParameters(List<JavaType> formals, JavaType site, Set<Type> visited) { TypeSubstitution typeSubstitution = new TypeSubstitution(); if (site.isParameterized()) { typeSubstitution = ((ParametrizedTypeJavaType) site).typeSubstitution; } TypeJavaSymbol siteSymbol = site.getSymbol(); List<JavaType> newFormals = formals; Type superClass = siteSymbol.superClass(); if (superClass != null) { JavaType newSuperClass = applySubstitution((JavaType) superClass, typeSubstitution); if(visited.add(newSuperClass)) { newFormals = applySiteSubstitutionToFormalParameters(newFormals, newSuperClass, visited); } } for (Type interfaceType : siteSymbol.interfaces()) { JavaType newInterfaceType = applySubstitution((JavaType) interfaceType, typeSubstitution); if(visited.add(newInterfaceType)) { newFormals = applySiteSubstitutionToFormalParameters(newFormals, newInterfaceType, visited); } } return applySubstitutionToFormalParameters(newFormals, typeSubstitution); }
private boolean isValidSubstitution(TypeSubstitution candidate, TypeVariableJavaType typeVar, JavaType typeParam, JavaType site) { for (JavaType bound : typeVar.bounds) { JavaType currentBound = applySubstitution(bound, candidate); while (currentBound.isTagged(JavaType.TYPEVAR) && !currentBound.symbol().owner().isMethodSymbol()) { JavaType newBound = candidate.substitutedType(currentBound); if (newBound == null && site.isParameterized()) { newBound = ((ParametrizedTypeJavaType) site).typeSubstitution.substitutedType(currentBound); } if (newBound == null) { return ((JavaSymbol.TypeJavaSymbol) site.symbol()).typeVariableTypes.contains(currentBound); } if (currentBound.equals(newBound)) { // exploring the same substitution, we cannot deduce anything break; } currentBound = newBound; } if (!isUnboundedWildcard(typeParam) && !typeParam.isSubtypeOf(currentBound)) { return false; } } return true; }
public List<JavaType> resolveTypeSubstitution(List<JavaType> formals, TypeSubstitution substitution) { return typeSubstitutionSolver.applySubstitutionToFormalParameters(formals, substitution); }
List<JavaType> applySiteSubstitutionToFormalParameters(List<JavaType> formals, JavaType site) { if(formals.isEmpty()) { return formals; } Set<Type> visited = new HashSet<>(); visited.add(site); return applySiteSubstitutionToFormalParameters(formals, site, visited); }
public JavaType parametrizedTypeWithErasure(ParametrizedTypeJavaType type) { return typeSubstitutionSolver.erasureSubstitution(type); }
public JavaType functionType(ParametrizedTypeJavaType javaType) { return typeSubstitutionSolver.functionType(javaType); }
return bestSoFar; TypeSubstitution substitution = typeSubstitutionSolver.getTypeSubstitution(methodJavaSymbol, callSite, typeParams, argTypes); if (substitution == null) { return bestSoFar; formals = typeSubstitutionSolver.applySiteSubstitutionToFormalParameters(formals, callSite); if(defSite != callSite) { formals = typeSubstitutionSolver.applySiteSubstitutionToFormalParameters(formals, defSite); formals = typeSubstitutionSolver.applySubstitutionToFormalParameters(formals, substitution); if (!isArgumentsAcceptable(argTypes, formals, methodJavaSymbol.isVarArgs(), looseInvocation)) { return bestSoFar; thrownTypes = erasure(thrownTypes); } else { returnType = typeSubstitutionSolver.getReturnType(returnType, defSite, callSite, substitution, mostSpecificMethod); thrownTypes = thrownTypes.stream() .map(t -> typeSubstitutionSolver.applySiteSubstitution(t, callSite)) .map(t -> typeSubstitutionSolver.applySubstitution(t, substitution)) .collect(Collectors.toList());
@CheckForNull TypeSubstitution getTypeSubstitution(JavaSymbol.MethodJavaSymbol method, JavaType site, List<JavaType> typeParams, List<JavaType> argTypes) { List<JavaType> formals = ((MethodJavaType) method.type).argTypes; TypeSubstitution substitution = new TypeSubstitution(); if (method.isParametrized() || constructParametrizedTypeWithoutSubstitution(method, site)) { if (!typeParams.isEmpty()) { substitution = getSubstitutionFromTypeParams(method.typeVariableTypes, typeParams); } else if (formals.isEmpty()) { // substitution can not be inferred, as it is not based on arguments, method call is still valid return substitution; } else { formals = applySiteSubstitutionToFormalParameters(formals, site); substitution = typeInferenceSolver.inferTypeSubstitution(method, formals, argTypes); } if (!isValidSubstitution(substitution, site)) { // check for valid substitution in supertypes, null if no valid substitution is found return getTypeSubstitutionFromSuperTypes(method, site, typeParams, argTypes); } } return substitution; }
JavaType getReturnType(@Nullable JavaType returnType, JavaType defSite, JavaType callSite, TypeSubstitution substitution, JavaSymbol.MethodJavaSymbol method) { JavaType resultType = returnType; if (method.isConstructor()) { if (constructParametrizedTypeWithoutSubstitution(method, defSite)) { resultType = applySubstitution(defSite, substitution); } else { return defSite; } } // As per getClass javadoc: // The actual result type [of getClass] is Class<? extends |X|> where |X| is the erasure of the static type of the expression on which getClass is called. if(defSite == symbols.objectType && "getClass".equals(method.name())) { TypeJavaSymbol classSymbol = symbols.classType.symbol; JavaType wildcardType = parametrizedTypeCache.getWildcardType(callSite.erasure(), WildCardType.BoundType.EXTENDS); resultType = parametrizedTypeCache.getParametrizedTypeType(classSymbol, new TypeSubstitution().add(classSymbol.typeVariableTypes.get(0), wildcardType)); } resultType = applySiteSubstitution(resultType, defSite); if (callSite != defSite) { resultType = applySiteSubstitution(resultType, callSite); } resultType = applySubstitution(resultType, substitution); if (!isReturnTypeCompletelySubstituted(resultType, method.typeVariableTypes) || (method.isConstructor() && !isReturnTypeCompletelySubstituted(resultType, defSite.symbol.typeVariableTypes))) { resultType = symbols.deferedType(resultType); } return resultType; }
@Override protected ClassJavaType substitutedType(ClassJavaType type) { return (ClassJavaType) typeSubstitutionSolver.applySubstitution(type, typeSubstitution); } }
public JavaType resolveTypeSubstitutionWithDiamondOperator(ParametrizedTypeJavaType type, JavaType definition) { ParametrizedTypeJavaType result = type; if (definition.isParameterized()) { TypeSubstitution substitution = TypeSubstitutionSolver.substitutionFromSuperType(type, (ParametrizedTypeJavaType) definition); result = (ParametrizedTypeJavaType) typeSubstitutionSolver.applySubstitution(type, substitution); } return typeSubstitutionSolver.erasureSubstitution(result); }
@VisibleForTesting List<JavaType> applySiteSubstitutionToFormalParameters(List<JavaType> formals, JavaType site, Set<Type> visited) { TypeSubstitution typeSubstitution = new TypeSubstitution(); if (site.isParameterized()) { typeSubstitution = ((ParametrizedTypeJavaType) site).typeSubstitution; } TypeJavaSymbol siteSymbol = site.getSymbol(); List<JavaType> newFormals = formals; Type superClass = siteSymbol.superClass(); if (superClass != null) { JavaType newSuperClass = applySubstitution((JavaType) superClass, typeSubstitution); if(visited.add(newSuperClass)) { newFormals = applySiteSubstitutionToFormalParameters(newFormals, newSuperClass, visited); } } for (Type interfaceType : siteSymbol.interfaces()) { JavaType newInterfaceType = applySubstitution((JavaType) interfaceType, typeSubstitution); if(visited.add(newInterfaceType)) { newFormals = applySiteSubstitutionToFormalParameters(newFormals, newInterfaceType, visited); } } return applySubstitutionToFormalParameters(newFormals, typeSubstitution); }