diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/kotlinSignature/SignaturesPropagation.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/kotlinSignature/SignaturesPropagation.java new file mode 100644 index 00000000000..09e7b0ee773 --- /dev/null +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/kotlinSignature/SignaturesPropagation.java @@ -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 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 typesFromSuper, + boolean covariantPosition + ) { + if (ErrorUtils.isErrorType(autoType)) { + return autoType; + } + + boolean resultNullable = returnTypeMustBeNullable(autoType, typesFromSuper, covariantPosition); + List 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 getTypeArgsOfReturnType(@NotNull JetType autoType, @NotNull Collection typesFromSuper) { + TypeConstructor typeConstructor = autoType.getConstructor(); + List autoArguments = autoType.getArguments(); + + if (!(typeConstructor.getDeclarationDescriptor() instanceof ClassDescriptor)) { + return autoArguments; + } + + List> typeArgumentsFromSuper = calculateTypeArgumentsFromSuper(autoType, typesFromSuper); + + // Modify type arguments using info from typesFromSuper + List 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 projectionsFromSuper = typeArgumentsFromSuper.get(i); + Collection 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 projectionsFromSuper) { + Set 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 getTypes(@NotNull List projections) { + List types = Lists.newArrayList(); + for (TypeProjection projection : projections) { + types.add(projection.getType()); + } + return types; + } + + // Returns list with type arguments info from supertypes + private static List> calculateTypeArgumentsFromSuper( + @NotNull JetType autoType, + @NotNull Collection 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 substitution = SubstitutionUtils.buildDeepSubstitutionMultimap( + TypeUtils.makeUnsubstitutedType(klass, null)); + + // for each parameter of autoType, hold arguments in corresponding supertypes + List> parameterToArgTypesFromSuper = Lists.newArrayList(); + for (TypeProjection ignored : autoType.getArguments()) { + parameterToArgTypesFromSuper.add(new ArrayList()); + } + + // Enumerate all types from super and all its parameters + for (JetType typeFromSuper : typesFromSuper) { + List 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 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 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() { + } +} diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaFunctionResolver.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaFunctionResolver.java index c7d1aeef4ad..61ae730c53d 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaFunctionResolver.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaFunctionResolver.java @@ -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 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 typesFromSuper, - boolean covariantPosition - ) { - if (ErrorUtils.isErrorType(autoType)) { - return autoType; - } - - boolean resultNullable = returnTypeMustBeNullable(autoType, typesFromSuper, covariantPosition); - List 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 getTypeArgsOfReturnType(@NotNull JetType autoType, @NotNull Collection typesFromSuper) { - TypeConstructor typeConstructor = autoType.getConstructor(); - List autoArguments = autoType.getArguments(); - - if (!(typeConstructor.getDeclarationDescriptor() instanceof ClassDescriptor)) { - return autoArguments; - } - - List> typeArgumentsFromSuper = calculateTypeArgumentsFromSuper(autoType, typesFromSuper); - - // Modify type arguments using info from typesFromSuper - List 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 projectionsFromSuper = typeArgumentsFromSuper.get(i); - Collection 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 projectionsFromSuper) { - Set 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 getTypes(@NotNull List projections) { - List types = Lists.newArrayList(); - for (TypeProjection projection : projections) { - types.add(projection.getType()); - } - return types; - } - - // Returns list with type arguments info from supertypes - private static List> calculateTypeArgumentsFromSuper( - @NotNull JetType autoType, - @NotNull Collection 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 substitution = SubstitutionUtils.buildDeepSubstitutionMultimap( - TypeUtils.makeUnsubstitutedType(klass, null)); - - // for each parameter of autoType, hold arguments in corresponding supertypes - List> parameterToArgTypesFromSuper = Lists.newArrayList(); - for (TypeProjection ignored : autoType.getArguments()) { - parameterToArgTypesFromSuper.add(new ArrayList()); - } - - // Enumerate all types from super and all its parameters - for (JetType typeFromSuper : typesFromSuper) { - List 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 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 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 methodTypeParameters = functionDescriptor.getValueParameters(); String methodName = functionDescriptor.getName().getName();