From 08c074c5be2a8b4ab268d1781e8ee67c246d4ecc Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Thu, 3 May 2012 17:08:25 +0400 Subject: [PATCH] SubstitutionUtils extracted from TypeUtils --- .../resolve/java/JavaDescriptorResolver.java | 8 +- .../resolve/java/JavaTypeTransformer.java | 4 +- .../lang/descriptors/ClassDescriptorImpl.java | 3 +- .../MutableClassDescriptorLite.java | 2 +- .../lang/resolve/TypeHierarchyResolver.java | 8 +- .../jet/lang/resolve/TypeResolver.java | 2 +- .../jet/lang/types/SubstitutionUtils.java | 138 ++++++++++++++++++ .../jet/lang/types/TypeSubstitutor.java | 4 +- .../jetbrains/jet/lang/types/TypeUtils.java | 102 ++----------- .../BasicExpressionTypingVisitor.java | 6 +- 10 files changed, 166 insertions(+), 111 deletions(-) create mode 100644 compiler/frontend/src/org/jetbrains/jet/lang/types/SubstitutionUtils.java diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java index b3787b5592c..8844466d01e 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java @@ -92,11 +92,7 @@ import org.jetbrains.jet.lang.resolve.constants.NullValue; import org.jetbrains.jet.lang.resolve.constants.ShortValue; import org.jetbrains.jet.lang.resolve.constants.StringValue; import org.jetbrains.jet.lang.resolve.java.kt.JetClassAnnotation; -import org.jetbrains.jet.lang.types.ErrorUtils; -import org.jetbrains.jet.lang.types.JetType; -import org.jetbrains.jet.lang.types.TypeSubstitutor; -import org.jetbrains.jet.lang.types.TypeUtils; -import org.jetbrains.jet.lang.types.Variance; +import org.jetbrains.jet.lang.types.*; import org.jetbrains.jet.lang.types.lang.JetStandardClasses; import org.jetbrains.jet.lang.types.lang.JetStandardLibrary; import org.jetbrains.jet.rt.signature.JetSignatureAdapter; @@ -1583,7 +1579,7 @@ public class JavaDescriptorResolver { private TypeSubstitutor createSubstitutorForGenericSupertypes(@Nullable ClassDescriptor classDescriptor) { TypeSubstitutor typeSubstitutor; if (classDescriptor != null) { - typeSubstitutor = TypeUtils.buildDeepSubstitutor(classDescriptor.getDefaultType()); + typeSubstitutor = SubstitutionUtils.buildDeepSubstitutor(classDescriptor.getDefaultType()); } else { typeSubstitutor = TypeSubstitutor.EMPTY; diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaTypeTransformer.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaTypeTransformer.java index 8b853b146f9..9afa41e38ff 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaTypeTransformer.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaTypeTransformer.java @@ -79,7 +79,7 @@ public class JavaTypeTransformer { @Override public TypeProjection visitWildcardType(PsiWildcardType wildcardType) { if (!wildcardType.isBounded()) { - return TypeUtils.makeStarProjection(typeParameterDescriptor); + return SubstitutionUtils.makeStarProjection(typeParameterDescriptor); } Variance variance = wildcardType.isExtends() ? Variance.OUT_VARIANCE : Variance.IN_VARIANCE; @@ -174,7 +174,7 @@ public class JavaTypeTransformer { if (classType.isRaw()) { List parameters = classData.getTypeConstructor().getParameters(); for (TypeParameterDescriptor parameter : parameters) { - arguments.add(TypeUtils.makeStarProjection(parameter)); + arguments.add(SubstitutionUtils.makeStarProjection(parameter)); } } else { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/ClassDescriptorImpl.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/ClassDescriptorImpl.java index 5929c950711..58b821afa3f 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/ClassDescriptorImpl.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/ClassDescriptorImpl.java @@ -97,7 +97,8 @@ public class ClassDescriptorImpl extends DeclarationDescriptorImpl implements Cl if (typeConstructor.getParameters().isEmpty()) { return memberDeclarations; } - Map substitutionContext = TypeUtils.buildSubstitutionContext(typeConstructor.getParameters(), typeArguments); + Map substitutionContext = SubstitutionUtils + .buildSubstitutionContext(typeConstructor.getParameters(), typeArguments); return new SubstitutingScope(memberDeclarations, TypeSubstitutor.create(substitutionContext)); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/MutableClassDescriptorLite.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/MutableClassDescriptorLite.java index 3fad662a0ea..ef24b557129 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/MutableClassDescriptorLite.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/MutableClassDescriptorLite.java @@ -139,7 +139,7 @@ public class MutableClassDescriptorLite extends MutableDeclarationDescriptor imp if (typeArguments.isEmpty()) return scopeForMemberLookup; List typeParameters = getTypeConstructor().getParameters(); - Map substitutionContext = TypeUtils.buildSubstitutionContext(typeParameters, typeArguments); + Map substitutionContext = SubstitutionUtils.buildSubstitutionContext(typeParameters, typeArguments); return new SubstitutingScope(scopeForMemberLookup, TypeSubstitutor.create(substitutionContext)); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeHierarchyResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeHierarchyResolver.java index f168cf409a9..6135ed5a0a0 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeHierarchyResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeHierarchyResolver.java @@ -29,10 +29,7 @@ import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.scopes.JetScope; import org.jetbrains.jet.lang.resolve.scopes.WritableScope; import org.jetbrains.jet.lang.resolve.scopes.WriteThroughScope; -import org.jetbrains.jet.lang.types.JetType; -import org.jetbrains.jet.lang.types.TypeConstructor; -import org.jetbrains.jet.lang.types.TypeProjection; -import org.jetbrains.jet.lang.types.TypeUtils; +import org.jetbrains.jet.lang.types.*; import org.jetbrains.jet.lang.types.checker.JetTypeChecker; import org.jetbrains.jet.lexer.JetTokens; @@ -379,7 +376,8 @@ public class TypeHierarchyResolver { private void checkSupertypesForConsistency() { for (MutableClassDescriptor mutableClassDescriptor : topologicalOrder) { - Multimap multimap = TypeUtils.buildDeepSubstitutionMultimap(mutableClassDescriptor.getDefaultType()); + Multimap multimap = SubstitutionUtils + .buildDeepSubstitutionMultimap(mutableClassDescriptor.getDefaultType()); for (Map.Entry> entry : multimap.asMap().entrySet()) { Collection projections = entry.getValue(); if (projections.size() > 1) { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeResolver.java index 1b5ed4faee3..e27a69392b9 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeResolver.java @@ -244,7 +244,7 @@ public class TypeResolver { List parameters = constructor.getParameters(); if (parameters.size() > i) { TypeParameterDescriptor parameterDescriptor = parameters.get(i); - arguments.add(TypeUtils.makeStarProjection(parameterDescriptor)); + arguments.add(SubstitutionUtils.makeStarProjection(parameterDescriptor)); } else { arguments.add(new TypeProjection(Variance.OUT_VARIANCE, ErrorUtils.createErrorType("*"))); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/SubstitutionUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/SubstitutionUtils.java new file mode 100644 index 00000000000..c50f40dfb81 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/SubstitutionUtils.java @@ -0,0 +1,138 @@ +/* + * 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.types; + +import com.google.common.collect.Maps; +import com.google.common.collect.Multimap; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor; +import org.jetbrains.jet.lang.types.lang.JetStandardClasses; +import org.jetbrains.jet.util.CommonSuppliers; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @author abreslav + */ +public class SubstitutionUtils { + @NotNull + public static Map buildSubstitutionContext(@NotNull JetType context) { + return buildSubstitutionContext(context.getConstructor().getParameters(), context.getArguments()); + } + + /** + * Builds a context with all the supertypes' parameters substituted + */ + @NotNull + public static TypeSubstitutor buildDeepSubstitutor(@NotNull JetType type) { + Map substitution = Maps.newHashMap(); + TypeSubstitutor typeSubstitutor = TypeSubstitutor.create(substitution); + // we use the mutability of the map here + fillInDeepSubstitutor(type, typeSubstitutor, substitution, null); + return typeSubstitutor; + } + + @NotNull + public static Multimap buildDeepSubstitutionMultimap(@NotNull JetType type) { + Multimap fullSubstitution = CommonSuppliers.newLinkedHashSetHashSetMultimap(); + Map substitution = Maps.newHashMap(); + TypeSubstitutor typeSubstitutor = TypeSubstitutor.create(substitution); + // we use the mutability of the map here + fillInDeepSubstitutor(type, typeSubstitutor, substitution, fullSubstitution); + return fullSubstitution; + } + + // we use the mutability of the substitution map here + private static void fillInDeepSubstitutor(@NotNull JetType context, @NotNull TypeSubstitutor substitutor, @NotNull Map substitution, @Nullable Multimap fullSubstitution) { + List parameters = context.getConstructor().getParameters(); + List arguments = context.getArguments(); + + if (parameters.size() != arguments.size()) { + throw new IllegalStateException(); + } + + for (int i = 0; i < arguments.size(); i++) { + TypeProjection argument = arguments.get(i); + TypeParameterDescriptor typeParameterDescriptor = parameters.get(i); + + JetType substitute = substitutor.substitute(argument.getType(), Variance.INVARIANT); + assert substitute != null; + TypeProjection substitutedTypeProjection = new TypeProjection(argument.getProjectionKind(), substitute); + substitution.put(typeParameterDescriptor.getTypeConstructor(), substitutedTypeProjection); + if (fullSubstitution != null) { + fullSubstitution.put(typeParameterDescriptor.getTypeConstructor(), substitutedTypeProjection); + } + } + if (JetStandardClasses.isNothingOrNullableNothing(context)) return; + for (JetType supertype : context.getConstructor().getSupertypes()) { + fillInDeepSubstitutor(supertype, substitutor, substitution, fullSubstitution); + } + } + + @NotNull + public static Map buildSubstitutionContext(@NotNull List parameters, @NotNull List contextArguments) { + Map parameterValues = new HashMap(); + fillInSubstitutionContext(parameters, contextArguments, parameterValues); + return parameterValues; + } + + private static void fillInSubstitutionContext(List parameters, List contextArguments, Map parameterValues) { + for (int i = 0, parametersSize = parameters.size(); i < parametersSize; i++) { + TypeParameterDescriptor parameter = parameters.get(i); + TypeProjection value = contextArguments.get(i); + parameterValues.put(parameter.getTypeConstructor(), value); + } + } + + @NotNull + public static TypeProjection makeStarProjection(@NotNull TypeParameterDescriptor parameterDescriptor) { + return new TypeProjection(Variance.OUT_VARIANCE, parameterDescriptor.getUpperBoundsAsType()); + } + + public static boolean hasUnsubstitutedTypeParameters(JetType type) { + if (type.getConstructor().getDeclarationDescriptor() instanceof TypeParameterDescriptor) { + return true; + } + + for(TypeProjection proj : type.getArguments()) { + if(hasUnsubstitutedTypeParameters(proj.getType())) { + return true; + } + } + + return false; + } + + public static void assertNotImmediatelyRecursive(Map context) { + // Make sure we never replace a T with "Foo" or something similar, + // because the substitution will not terminate in this case + // This check is not complete. It does not find cases like + // T -> Foo + // T -> Bar + + for (Map.Entry entry : context.entrySet()) { + TypeConstructor key = entry.getKey(); + TypeProjection value = entry.getValue(); + if (TypeUtils.typeConstructorUsedInType(key, value.getType())) { + throw new IllegalStateException("Immediately recursive substitution: " + context + "\nProblematic parameter: " + key + " -> " + value); + } + } + } +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/TypeSubstitutor.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/TypeSubstitutor.java index e2487877d0d..6e5e4e8e7e0 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/TypeSubstitutor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/TypeSubstitutor.java @@ -127,7 +127,7 @@ public class TypeSubstitutor { } public static TypeSubstitutor create(@NotNull JetType context) { - return create(TypeUtils.buildSubstitutionContext(context)); + return create(SubstitutionUtils.buildSubstitutionContext(context)); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -254,7 +254,7 @@ public class TypeSubstitutor { assert typeToSubstituteIn.getConstructor().getDeclarationDescriptor() instanceof TypeParameterDescriptor; if (!allows(parameterVariance, passedProjectionKind)) { - return TypeUtils.makeStarProjection(correspondingTypeParameter); + return SubstitutionUtils.makeStarProjection(correspondingTypeParameter); } return substitutionResult(correspondingTypeParameter, effectiveContextVariance, passedProjectionKind, projectionValue, recursionDepth + 1); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/TypeUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/TypeUtils.java index 4099b7a2959..e7c6b4a7434 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/TypeUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/TypeUtils.java @@ -18,7 +18,6 @@ package org.jetbrains.jet.lang.types; import com.google.common.collect.Lists; import com.google.common.collect.Maps; -import com.google.common.collect.Multimap; import com.google.common.collect.Sets; import com.intellij.util.Processor; import org.jetbrains.annotations.NotNull; @@ -36,7 +35,6 @@ import org.jetbrains.jet.lang.resolve.scopes.ChainedScope; import org.jetbrains.jet.lang.resolve.scopes.JetScope; import org.jetbrains.jet.lang.types.checker.JetTypeChecker; import org.jetbrains.jet.lang.types.lang.JetStandardClasses; -import org.jetbrains.jet.util.CommonSuppliers; import java.util.*; @@ -401,80 +399,6 @@ public class TypeUtils { return result; } - @NotNull - public static Map buildSubstitutionContext(@NotNull JetType context) { - return buildSubstitutionContext(context.getConstructor().getParameters(), context.getArguments()); - } - - /** - * Builds a context with all the supertypes' parameters substituted - */ - @NotNull - public static TypeSubstitutor buildDeepSubstitutor(@NotNull JetType type) { - Map substitution = Maps.newHashMap(); - TypeSubstitutor typeSubstitutor = TypeSubstitutor.create(substitution); - // we use the mutability of the map here - fillInDeepSubstitutor(type, typeSubstitutor, substitution, null); - return typeSubstitutor; - } - - @NotNull - public static Multimap buildDeepSubstitutionMultimap(@NotNull JetType type) { - Multimap fullSubstitution = CommonSuppliers.newLinkedHashSetHashSetMultimap(); - Map substitution = Maps.newHashMap(); - TypeSubstitutor typeSubstitutor = TypeSubstitutor.create(substitution); - // we use the mutability of the map here - fillInDeepSubstitutor(type, typeSubstitutor, substitution, fullSubstitution); - return fullSubstitution; - } - - // we use the mutability of the substitution map here - private static void fillInDeepSubstitutor(@NotNull JetType context, @NotNull TypeSubstitutor substitutor, @NotNull Map substitution, @Nullable Multimap fullSubstitution) { - List parameters = context.getConstructor().getParameters(); - List arguments = context.getArguments(); - - if (parameters.size() != arguments.size()) { - throw new IllegalStateException(); - } - - for (int i = 0; i < arguments.size(); i++) { - TypeProjection argument = arguments.get(i); - TypeParameterDescriptor typeParameterDescriptor = parameters.get(i); - - JetType substitute = substitutor.substitute(argument.getType(), Variance.INVARIANT); - assert substitute != null; - TypeProjection substitutedTypeProjection = new TypeProjection(argument.getProjectionKind(), substitute); - substitution.put(typeParameterDescriptor.getTypeConstructor(), substitutedTypeProjection); - if (fullSubstitution != null) { - fullSubstitution.put(typeParameterDescriptor.getTypeConstructor(), substitutedTypeProjection); - } - } - if (JetStandardClasses.isNothingOrNullableNothing(context)) return; - for (JetType supertype : context.getConstructor().getSupertypes()) { - fillInDeepSubstitutor(supertype, substitutor, substitution, fullSubstitution); - } - } - - @NotNull - public static Map buildSubstitutionContext(@NotNull List parameters, @NotNull List contextArguments) { - Map parameterValues = new HashMap(); - fillInSubstitutionContext(parameters, contextArguments, parameterValues); - return parameterValues; - } - - private static void fillInSubstitutionContext(List parameters, List contextArguments, Map parameterValues) { - for (int i = 0, parametersSize = parameters.size(); i < parametersSize; i++) { - TypeParameterDescriptor parameter = parameters.get(i); - TypeProjection value = contextArguments.get(i); - parameterValues.put(parameter.getTypeConstructor(), value); - } - } - - @NotNull - public static TypeProjection makeStarProjection(@NotNull TypeParameterDescriptor parameterDescriptor) { - return new TypeProjection(Variance.OUT_VARIANCE, parameterDescriptor.getUpperBoundsAsType()); - } - private static void collectImmediateSupertypes(@NotNull JetType type, @NotNull Collection result) { TypeSubstitutor substitutor = TypeSubstitutor.create(type); for (JetType supertype : type.getConstructor().getSupertypes()) { @@ -548,21 +472,19 @@ public class TypeUtils { return new ArrayList(classDescriptors); } - public static boolean hasUnsubstitutedTypeParameters(JetType type) { - if (type.getConstructor().getDeclarationDescriptor() instanceof TypeParameterDescriptor) { - return true; - } - - for(TypeProjection proj : type.getArguments()) { - if(hasUnsubstitutedTypeParameters(proj.getType())) { - return true; - } - } - - return false; - } - public static boolean equalTypes(@NotNull JetType a, @NotNull JetType b) { return JetTypeChecker.INSTANCE.isSubtypeOf(a, b) && JetTypeChecker.INSTANCE.isSubtypeOf(b, a); } + + public static boolean typeConstructorUsedInType(@NotNull TypeConstructor key, @NotNull JetType value) { + if (value.getConstructor() == key) return true; + for (TypeProjection projection : value.getArguments()) { + if (typeConstructorUsedInType(key, projection.getType())) { + return true; + } + } + return false; + } + + } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java index 8be063268e3..aecb9c5427e 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java @@ -285,7 +285,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { { Multimap typeSubstitutionMap = - TypeUtils.buildDeepSubstitutionMultimap(targetType); + SubstitutionUtils.buildDeepSubstitutionMultimap(targetType); for (int i = 0; i < actualType.getConstructor().getParameters().size(); ++i) { TypeProjection actualTypeParameter = actualType.getArguments().get(i); @@ -310,7 +310,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { (ClassDescriptor) targetType.getConstructor().getDeclarationDescriptor(), null); Multimap clearTypeSubstitutionMap = - TypeUtils.buildDeepSubstitutionMultimap(targetTypeClerared); + SubstitutionUtils.buildDeepSubstitutionMultimap(targetTypeClerared); Set clearSubstituted = new HashSet(); @@ -332,7 +332,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { } // "is List<*>" - if (typeProjection.equals(TypeUtils.makeStarProjection(typeParameter))) { + if (typeProjection.equals(SubstitutionUtils.makeStarProjection(typeParameter))) { continue; }