001    /*
002     * Copyright 2010-2014 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.jet.lang.types;
018    
019    import org.jetbrains.annotations.NotNull;
020    import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
021    import org.jetbrains.jet.lang.descriptors.SourceElement;
022    import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
023    import org.jetbrains.jet.lang.descriptors.impl.TypeParameterDescriptorImpl;
024    
025    import java.util.HashMap;
026    import java.util.List;
027    import java.util.Map;
028    
029    public class DescriptorSubstitutor {
030        private DescriptorSubstitutor() {
031        }
032    
033        @NotNull
034        public static TypeSubstitutor substituteTypeParameters(
035                @NotNull List<TypeParameterDescriptor> typeParameters,
036                @NotNull final TypeSubstitutor originalSubstitutor,
037                @NotNull DeclarationDescriptor newContainingDeclaration,
038                @NotNull List<TypeParameterDescriptor> result
039        ) {
040            final Map<TypeConstructor, TypeProjection> mutableSubstitution = new HashMap<TypeConstructor, TypeProjection>();
041            TypeSubstitutor substitutor = TypeSubstitutor.create(new TypeSubstitution() {
042                @Override
043                public TypeProjection get(TypeConstructor key) {
044                    if (originalSubstitutor.inRange(key)) {
045                        return originalSubstitutor.getSubstitution().get(key);
046                    }
047                    return mutableSubstitution.get(key);
048                }
049    
050                @Override
051                public boolean isEmpty() {
052                    return originalSubstitutor.isEmpty() && mutableSubstitution.isEmpty();
053                }
054    
055                @Override
056                public String toString() {
057                    return "DescriptorSubstitutor.substituteTypeParameters(" + mutableSubstitution + " / " + originalSubstitutor.getSubstitution() + ")";
058                }
059            });
060    
061            Map<TypeParameterDescriptor, TypeParameterDescriptorImpl> substitutedMap =
062                    new HashMap<TypeParameterDescriptor, TypeParameterDescriptorImpl>();
063            for (TypeParameterDescriptor descriptor : typeParameters) {
064                TypeParameterDescriptorImpl substituted = TypeParameterDescriptorImpl.createForFurtherModification(
065                        newContainingDeclaration,
066                        descriptor.getAnnotations(),
067                        descriptor.isReified(),
068                        descriptor.getVariance(),
069                        descriptor.getName(),
070                        descriptor.getIndex(),
071                        SourceElement.NO_SOURCE
072                );
073                substituted.setInitialized();
074    
075                mutableSubstitution.put(descriptor.getTypeConstructor(), new TypeProjectionImpl(substituted.getDefaultType()));
076    
077                substitutedMap.put(descriptor, substituted);
078                result.add(substituted);
079            }
080    
081            for (TypeParameterDescriptor descriptor : typeParameters) {
082                TypeParameterDescriptorImpl substituted = substitutedMap.get(descriptor);
083                for (JetType upperBound : descriptor.getUpperBounds()) {
084                    substituted.getUpperBounds().add(substitutor.substitute(upperBound, Variance.INVARIANT));
085                }
086            }
087    
088            return substitutor;
089        }
090    }