Moved all code relevant to signatures propagation to separate class.

#KT-2776 in progress
This commit is contained in:
Evgeny Gerashchenko
2012-11-13 15:25:31 +04:00
parent 00bed4a2a4
commit 94cad16d1d
2 changed files with 261 additions and 211 deletions
@@ -0,0 +1,253 @@
/*
* Copyright 2010-2012 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 org.jetbrains.jet.lang.resolve.java.kotlinSignature;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
import com.intellij.psi.HierarchicalMethodSignature;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.BindingTrace;
import org.jetbrains.jet.lang.resolve.java.MutableReadOnlyCollectionsMap;
import org.jetbrains.jet.lang.resolve.java.wrapper.PsiMethodWrapper;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.types.*;
import org.jetbrains.jet.lang.types.checker.TypeCheckingProcedure;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
public class SignaturesPropagation {
public static JetType modifyReturnTypeAccordingToSuperMethods(
@NotNull JetType autoType,
@NotNull PsiMethodWrapper method,
@NotNull BindingTrace trace
) {
Set<JetType> typesFromSuperMethods = Sets.newHashSet();
for (HierarchicalMethodSignature superSignature : method.getPsiMethod().getHierarchicalMethodSignature().getSuperSignatures()) {
DeclarationDescriptor superFun = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, superSignature.getMethod());
if (superFun instanceof FunctionDescriptor) {
typesFromSuperMethods.add(((FunctionDescriptor) superFun).getReturnType());
}
}
return modifyReturnTypeAccordingToSuperMethods(autoType, typesFromSuperMethods, true);
}
@NotNull
private static JetType modifyReturnTypeAccordingToSuperMethods(
@NotNull JetType autoType,
@NotNull Collection<JetType> typesFromSuper,
boolean covariantPosition
) {
if (ErrorUtils.isErrorType(autoType)) {
return autoType;
}
boolean resultNullable = returnTypeMustBeNullable(autoType, typesFromSuper, covariantPosition);
List<TypeProjection> resultArguments = getTypeArgsOfReturnType(autoType, typesFromSuper);
JetScope resultScope;
ClassifierDescriptor classifierDescriptor = getReturnTypeClassifier(autoType, typesFromSuper);
if (classifierDescriptor instanceof ClassDescriptor) {
resultScope = ((ClassDescriptor) classifierDescriptor).getMemberScope(resultArguments);
}
else {
resultScope = autoType.getMemberScope();
}
return new JetTypeImpl(autoType.getAnnotations(),
classifierDescriptor.getTypeConstructor(),
resultNullable,
resultArguments,
resultScope);
}
@NotNull
private static List<TypeProjection> getTypeArgsOfReturnType(@NotNull JetType autoType, @NotNull Collection<JetType> typesFromSuper) {
TypeConstructor typeConstructor = autoType.getConstructor();
List<TypeProjection> autoArguments = autoType.getArguments();
if (!(typeConstructor.getDeclarationDescriptor() instanceof ClassDescriptor)) {
return autoArguments;
}
List<List<TypeProjection>> typeArgumentsFromSuper = calculateTypeArgumentsFromSuper(autoType, typesFromSuper);
// Modify type arguments using info from typesFromSuper
List<TypeProjection> resultArguments = Lists.newArrayList();
for (int i = 0; i < autoArguments.size(); i++) {
TypeProjection argument = autoArguments.get(i);
TypeCheckingProcedure.EnrichedProjectionKind effectiveProjectionKind =
TypeCheckingProcedure.getEffectiveProjectionKind(typeConstructor.getParameters().get(i), argument);
JetType argumentType = argument.getType();
List<TypeProjection> projectionsFromSuper = typeArgumentsFromSuper.get(i);
Collection<JetType> argTypesFromSuper = getTypes(projectionsFromSuper);
boolean covariantPosition = effectiveProjectionKind == TypeCheckingProcedure.EnrichedProjectionKind.OUT;
JetType type = modifyReturnTypeAccordingToSuperMethods(argumentType, argTypesFromSuper, covariantPosition);
Variance variance = calculateArgumentVarianceFromSuper(argument, projectionsFromSuper);
resultArguments.add(new TypeProjection(variance, type));
}
return resultArguments;
}
private static Variance calculateArgumentVarianceFromSuper(TypeProjection argument, List<TypeProjection> projectionsFromSuper) {
Set<Variance> variancesInSuper = Sets.newHashSet();
for (TypeProjection projection : projectionsFromSuper) {
variancesInSuper.add(projection.getProjectionKind());
}
Variance defaultVariance = argument.getProjectionKind();
if (variancesInSuper.size() == 0) {
return defaultVariance;
}
else if (variancesInSuper.size() == 1) {
Variance varianceInSuper = variancesInSuper.iterator().next();
if (defaultVariance == Variance.INVARIANT || defaultVariance == varianceInSuper) {
return varianceInSuper;
}
else {
// TODO report error
return defaultVariance;
}
}
else {
// TODO report error
return defaultVariance;
}
}
@NotNull
private static List<JetType> getTypes(@NotNull List<TypeProjection> projections) {
List<JetType> types = Lists.newArrayList();
for (TypeProjection projection : projections) {
types.add(projection.getType());
}
return types;
}
// Returns list with type arguments info from supertypes
private static List<List<TypeProjection>> calculateTypeArgumentsFromSuper(
@NotNull JetType autoType,
@NotNull Collection<JetType> typesFromSuper
) {
ClassDescriptor klass = (ClassDescriptor) autoType.getConstructor().getDeclarationDescriptor();
// For each superclass of autoType's class and its parameters, hold their mapping to autoType's parameters
Multimap<TypeConstructor,TypeProjection> substitution = SubstitutionUtils.buildDeepSubstitutionMultimap(
TypeUtils.makeUnsubstitutedType(klass, null));
// for each parameter of autoType, hold arguments in corresponding supertypes
List<List<TypeProjection>> parameterToArgTypesFromSuper = Lists.newArrayList();
for (TypeProjection ignored : autoType.getArguments()) {
parameterToArgTypesFromSuper.add(new ArrayList<TypeProjection>());
}
// Enumerate all types from super and all its parameters
for (JetType typeFromSuper : typesFromSuper) {
List<TypeParameterDescriptor> typeFromSuperParameters = typeFromSuper.getConstructor().getParameters();
for (int i = 0; i < typeFromSuperParameters.size(); i++) {
TypeParameterDescriptor typeFromSuperParam = typeFromSuperParameters.get(i);
TypeProjection typeFromSuperArgType = typeFromSuper.getArguments().get(i);
// if it is mapped to autoType's parameter, then store it into map
for (TypeProjection projection : substitution.get(typeFromSuperParam.getTypeConstructor())) {
ClassifierDescriptor classifier = projection.getType().getConstructor().getDeclarationDescriptor();
if (classifier instanceof TypeParameterDescriptor && classifier.getContainingDeclaration() == klass) {
parameterToArgTypesFromSuper.get(((TypeParameterDescriptor) classifier).getIndex()).add(typeFromSuperArgType);
}
}
}
}
return parameterToArgTypesFromSuper;
}
private static boolean returnTypeMustBeNullable(JetType autoType, Collection<JetType> typesFromSuper, boolean covariantPosition) {
boolean someSupersNullable = false;
boolean someSupersNotNull = false;
for (JetType typeFromSuper : typesFromSuper) {
if (typeFromSuper.isNullable()) {
someSupersNullable = true;
}
else {
someSupersNotNull = true;
}
}
if (someSupersNotNull && someSupersNullable) {
//noinspection IfStatementWithIdenticalBranches
if (covariantPosition) {
return false;
}
else {
// TODO error!
return true;
}
}
if (!someSupersNotNull && !someSupersNullable) { // no types from super
return autoType.isNullable();
}
return someSupersNullable && autoType.isNullable();
}
@NotNull
private static ClassifierDescriptor getReturnTypeClassifier(@NotNull JetType autoType, @NotNull Collection<JetType> typesFromSuper) {
ClassifierDescriptor classifier = autoType.getConstructor().getDeclarationDescriptor();
if (!(classifier instanceof ClassDescriptor)) {
return classifier;
}
ClassDescriptor clazz = (ClassDescriptor) classifier;
MutableReadOnlyCollectionsMap collectionsMap = MutableReadOnlyCollectionsMap.getInstance();
if (collectionsMap.isMutableCollection(clazz)) {
boolean someSupersMutable = false;
boolean someSupersReadOnly = false;
for (JetType typeFromSuper : typesFromSuper) {
ClassifierDescriptor classifierFromSuper = typeFromSuper.getConstructor().getDeclarationDescriptor();
if (classifierFromSuper instanceof ClassDescriptor) {
ClassDescriptor classFromSuper = (ClassDescriptor) classifierFromSuper;
if (collectionsMap.isMutableCollection(classFromSuper)) {
someSupersMutable = true;
}
else if (collectionsMap.isReadOnlyCollection(classFromSuper)) {
someSupersReadOnly = true;
}
}
}
if (someSupersReadOnly && !someSupersMutable) {
return collectionsMap.convertMutableToReadOnly(clazz);
}
}
return classifier;
}
private SignaturesPropagation() {
}
}
@@ -17,9 +17,7 @@
package org.jetbrains.jet.lang.resolve.java.resolver;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
import com.intellij.psi.HierarchicalMethodSignature;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiType;
@@ -29,20 +27,23 @@ import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.resolve.*;
import org.jetbrains.jet.lang.resolve.java.*;
import org.jetbrains.jet.lang.resolve.java.kotlinSignature.AlternativeMethodSignatureData;
import org.jetbrains.jet.lang.resolve.java.kotlinSignature.SignaturesPropagation;
import org.jetbrains.jet.lang.resolve.java.kt.DescriptorKindUtils;
import org.jetbrains.jet.lang.resolve.java.provider.ClassPsiDeclarationProvider;
import org.jetbrains.jet.lang.resolve.java.provider.NamedMembers;
import org.jetbrains.jet.lang.resolve.java.provider.PsiDeclarationProvider;
import org.jetbrains.jet.lang.resolve.java.wrapper.PsiMethodWrapper;
import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.types.*;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.TypeUtils;
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
import org.jetbrains.jet.lang.types.checker.TypeCheckingProcedure;
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
import javax.inject.Inject;
import java.util.*;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import static org.jetbrains.jet.lang.resolve.java.provider.DeclarationOrigin.JAVA;
import static org.jetbrains.jet.lang.resolve.java.provider.DeclarationOrigin.KOTLIN;
@@ -135,15 +136,7 @@ public final class JavaFunctionResolver {
.resolveParameterDescriptors(functionDescriptorImpl, method.getParameters(), methodTypeVariableResolver);
JetType returnType = makeReturnType(returnPsiType, method, methodTypeVariableResolver);
Set<JetType> typesFromSuperMethods = Sets.newHashSet();
for (HierarchicalMethodSignature superSignature : method.getPsiMethod().getHierarchicalMethodSignature().getSuperSignatures()) {
DeclarationDescriptor superFun = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, superSignature.getMethod());
if (superFun instanceof FunctionDescriptor) {
typesFromSuperMethods.add(((FunctionDescriptor) superFun).getReturnType());
}
}
returnType = modifyReturnTypeAccordingToSuperMethods(returnType, typesFromSuperMethods, true);
returnType = SignaturesPropagation.modifyReturnTypeAccordingToSuperMethods(returnType, method, trace);
// TODO consider better place for this check
AlternativeMethodSignatureData alternativeMethodSignatureData =
@@ -291,202 +284,6 @@ public final class JavaFunctionResolver {
return r;
}
@NotNull
private static JetType modifyReturnTypeAccordingToSuperMethods(
@NotNull JetType autoType,
@NotNull Collection<JetType> typesFromSuper,
boolean covariantPosition
) {
if (ErrorUtils.isErrorType(autoType)) {
return autoType;
}
boolean resultNullable = returnTypeMustBeNullable(autoType, typesFromSuper, covariantPosition);
List<TypeProjection> resultArguments = getTypeArgsOfReturnType(autoType, typesFromSuper);
JetScope resultScope;
ClassifierDescriptor classifierDescriptor = getReturnTypeClassifier(autoType, typesFromSuper);
if (classifierDescriptor instanceof ClassDescriptor) {
resultScope = ((ClassDescriptor) classifierDescriptor).getMemberScope(resultArguments);
}
else {
resultScope = autoType.getMemberScope();
}
return new JetTypeImpl(autoType.getAnnotations(),
classifierDescriptor.getTypeConstructor(),
resultNullable,
resultArguments,
resultScope);
}
@NotNull
private static List<TypeProjection> getTypeArgsOfReturnType(@NotNull JetType autoType, @NotNull Collection<JetType> typesFromSuper) {
TypeConstructor typeConstructor = autoType.getConstructor();
List<TypeProjection> autoArguments = autoType.getArguments();
if (!(typeConstructor.getDeclarationDescriptor() instanceof ClassDescriptor)) {
return autoArguments;
}
List<List<TypeProjection>> typeArgumentsFromSuper = calculateTypeArgumentsFromSuper(autoType, typesFromSuper);
// Modify type arguments using info from typesFromSuper
List<TypeProjection> resultArguments = Lists.newArrayList();
for (int i = 0; i < autoArguments.size(); i++) {
TypeProjection argument = autoArguments.get(i);
TypeCheckingProcedure.EnrichedProjectionKind effectiveProjectionKind =
TypeCheckingProcedure.getEffectiveProjectionKind(typeConstructor.getParameters().get(i), argument);
JetType argumentType = argument.getType();
List<TypeProjection> projectionsFromSuper = typeArgumentsFromSuper.get(i);
Collection<JetType> argTypesFromSuper = getTypes(projectionsFromSuper);
boolean covariantPosition = effectiveProjectionKind == TypeCheckingProcedure.EnrichedProjectionKind.OUT;
JetType type = modifyReturnTypeAccordingToSuperMethods(argumentType, argTypesFromSuper, covariantPosition);
Variance variance = calculateArgumentVarianceFromSuper(argument, projectionsFromSuper);
resultArguments.add(new TypeProjection(variance, type));
}
return resultArguments;
}
private static Variance calculateArgumentVarianceFromSuper(TypeProjection argument, List<TypeProjection> projectionsFromSuper) {
Set<Variance> variancesInSuper = Sets.newHashSet();
for (TypeProjection projection : projectionsFromSuper) {
variancesInSuper.add(projection.getProjectionKind());
}
Variance defaultVariance = argument.getProjectionKind();
if (variancesInSuper.size() == 0) {
return defaultVariance;
}
else if (variancesInSuper.size() == 1) {
Variance varianceInSuper = variancesInSuper.iterator().next();
if (defaultVariance == Variance.INVARIANT || defaultVariance == varianceInSuper) {
return varianceInSuper;
}
else {
// TODO report error
return defaultVariance;
}
}
else {
// TODO report error
return defaultVariance;
}
}
@NotNull
private static List<JetType> getTypes(@NotNull List<TypeProjection> projections) {
List<JetType> types = Lists.newArrayList();
for (TypeProjection projection : projections) {
types.add(projection.getType());
}
return types;
}
// Returns list with type arguments info from supertypes
private static List<List<TypeProjection>> calculateTypeArgumentsFromSuper(
@NotNull JetType autoType,
@NotNull Collection<JetType> typesFromSuper
) {
ClassDescriptor klass = (ClassDescriptor) autoType.getConstructor().getDeclarationDescriptor();
// For each superclass of autoType's class and its parameters, hold their mapping to autoType's parameters
Multimap<TypeConstructor,TypeProjection> substitution = SubstitutionUtils.buildDeepSubstitutionMultimap(
TypeUtils.makeUnsubstitutedType(klass, null));
// for each parameter of autoType, hold arguments in corresponding supertypes
List<List<TypeProjection>> parameterToArgTypesFromSuper = Lists.newArrayList();
for (TypeProjection ignored : autoType.getArguments()) {
parameterToArgTypesFromSuper.add(new ArrayList<TypeProjection>());
}
// Enumerate all types from super and all its parameters
for (JetType typeFromSuper : typesFromSuper) {
List<TypeParameterDescriptor> typeFromSuperParameters = typeFromSuper.getConstructor().getParameters();
for (int i = 0; i < typeFromSuperParameters.size(); i++) {
TypeParameterDescriptor typeFromSuperParam = typeFromSuperParameters.get(i);
TypeProjection typeFromSuperArgType = typeFromSuper.getArguments().get(i);
// if it is mapped to autoType's parameter, then store it into map
for (TypeProjection projection : substitution.get(typeFromSuperParam.getTypeConstructor())) {
ClassifierDescriptor classifier = projection.getType().getConstructor().getDeclarationDescriptor();
if (classifier instanceof TypeParameterDescriptor && classifier.getContainingDeclaration() == klass) {
parameterToArgTypesFromSuper.get(((TypeParameterDescriptor) classifier).getIndex()).add(typeFromSuperArgType);
}
}
}
}
return parameterToArgTypesFromSuper;
}
private static boolean returnTypeMustBeNullable(JetType autoType, Collection<JetType> typesFromSuper, boolean covariantPosition) {
boolean someSupersNullable = false;
boolean someSupersNotNull = false;
for (JetType typeFromSuper : typesFromSuper) {
if (typeFromSuper.isNullable()) {
someSupersNullable = true;
}
else {
someSupersNotNull = true;
}
}
if (someSupersNotNull && someSupersNullable) {
//noinspection IfStatementWithIdenticalBranches
if (covariantPosition) {
return false;
}
else {
// TODO error!
return true;
}
}
if (!someSupersNotNull && !someSupersNullable) { // no types from super
return autoType.isNullable();
}
return someSupersNullable && autoType.isNullable();
}
@NotNull
private static ClassifierDescriptor getReturnTypeClassifier(@NotNull JetType autoType, @NotNull Collection<JetType> typesFromSuper) {
ClassifierDescriptor classifier = autoType.getConstructor().getDeclarationDescriptor();
if (!(classifier instanceof ClassDescriptor)) {
return classifier;
}
ClassDescriptor clazz = (ClassDescriptor) classifier;
MutableReadOnlyCollectionsMap collectionsMap = MutableReadOnlyCollectionsMap.getInstance();
if (collectionsMap.isMutableCollection(clazz)) {
boolean someSupersMutable = false;
boolean someSupersReadOnly = false;
for (JetType typeFromSuper : typesFromSuper) {
ClassifierDescriptor classifierFromSuper = typeFromSuper.getConstructor().getDeclarationDescriptor();
if (classifierFromSuper instanceof ClassDescriptor) {
ClassDescriptor classFromSuper = (ClassDescriptor) classifierFromSuper;
if (collectionsMap.isMutableCollection(classFromSuper)) {
someSupersMutable = true;
}
else if (collectionsMap.isReadOnlyCollection(classFromSuper)) {
someSupersReadOnly = true;
}
}
}
if (someSupersReadOnly && !someSupersMutable) {
return collectionsMap.convertMutableToReadOnly(clazz);
}
}
return classifier;
}
private static boolean isEnumSpecialMethod(@NotNull FunctionDescriptor functionDescriptor) {
List<ValueParameterDescriptor> methodTypeParameters = functionDescriptor.getValueParameters();
String methodName = functionDescriptor.getName().getName();