001 /*
002 * Copyright 2010-2015 JetBrains s.r.o.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017 package org.jetbrains.kotlin.types;
018
019 import com.google.common.collect.LinkedHashMultimap;
020 import com.google.common.collect.Maps;
021 import com.google.common.collect.Multimap;
022 import org.jetbrains.annotations.NotNull;
023 import org.jetbrains.annotations.Nullable;
024 import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor;
025 import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
026
027 import java.util.List;
028 import java.util.Map;
029
030 public class SubstitutionUtils {
031 private SubstitutionUtils() {
032 }
033
034 /**
035 * Builds a context with all the supertypes' parameters substituted
036 */
037 @NotNull
038 public static TypeSubstitutor buildDeepSubstitutor(@NotNull JetType type) {
039 Map<TypeConstructor, TypeProjection> substitution = Maps.newHashMap();
040 TypeSubstitutor typeSubstitutor = TypeSubstitutor.create(substitution);
041 // we use the mutability of the map here
042 fillInDeepSubstitutor(type, typeSubstitutor, substitution, null);
043 return typeSubstitutor;
044 }
045
046 /**
047 For each supertype of a given type, we map type parameters to type arguments.
048
049 For instance, we have the following class hierarchy:
050 trait Iterable<out T>
051 trait Collection<out E>: Iterable<E>
052 trait MyFooCollection<F>: Collection<Foo<F>>
053
054 For MyFooCollection<out CharSequence>, the following multimap will be returned:
055 T declared in Iterable -> Foo<out CharSequence>
056 E declared in Collection -> Foo<out CharSequence>
057 F declared in MyFooCollection -> out CharSequence
058 */
059 @NotNull
060 public static Multimap<TypeConstructor, TypeProjection> buildDeepSubstitutionMultimap(@NotNull JetType type) {
061 Multimap<TypeConstructor, TypeProjection> fullSubstitution = LinkedHashMultimap.create();
062 Map<TypeConstructor, TypeProjection> substitution = Maps.newHashMap();
063 TypeSubstitutor typeSubstitutor = TypeSubstitutor.create(substitution);
064 // we use the mutability of the map here
065 fillInDeepSubstitutor(type, typeSubstitutor, substitution, fullSubstitution);
066 return fullSubstitution;
067 }
068
069 // we use the mutability of the substitution map here
070 private static void fillInDeepSubstitutor(
071 @NotNull JetType context,
072 @NotNull TypeSubstitutor substitutor,
073 @NotNull Map<TypeConstructor, TypeProjection> substitution,
074 @Nullable Multimap<TypeConstructor, TypeProjection> fullSubstitution
075 ) {
076 List<TypeParameterDescriptor> parameters = context.getConstructor().getParameters();
077 List<TypeProjection> arguments = context.getArguments();
078
079 if (parameters.size() != arguments.size()) {
080 throw new IllegalStateException();
081 }
082
083 for (int i = 0; i < arguments.size(); i++) {
084 TypeProjection argument = arguments.get(i);
085 TypeParameterDescriptor parameter = parameters.get(i);
086
087 TypeProjection substitute = substitutor.substitute(argument);
088 assert substitute != null;
089 substitution.put(parameter.getTypeConstructor(), substitute);
090 if (fullSubstitution != null) {
091 fullSubstitution.put(parameter.getTypeConstructor(), substitute);
092 }
093 }
094 if (KotlinBuiltIns.isNothingOrNullableNothing(context)) return;
095 for (JetType supertype : context.getConstructor().getSupertypes()) {
096 fillInDeepSubstitutor(supertype, substitutor, substitution, fullSubstitution);
097 }
098 }
099 }