001    /*
002     * Copyright 2010-2013 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.descriptors.impl;
018    
019    import org.jetbrains.annotations.NotNull;
020    import org.jetbrains.annotations.Nullable;
021    import org.jetbrains.jet.lang.descriptors.*;
022    import org.jetbrains.jet.lang.resolve.BindingTrace;
023    import org.jetbrains.jet.lang.resolve.TraceBasedRedeclarationHandler;
024    import org.jetbrains.jet.lang.resolve.scopes.JetScope;
025    import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
026    import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl;
027    import org.jetbrains.jet.lang.types.*;
028    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
029    
030    import java.util.*;
031    
032    public class FunctionDescriptorUtil {
033        private static final TypeSubstitutor MAKE_TYPE_PARAMETERS_FRESH = TypeSubstitutor.create(new TypeSubstitution() {
034    
035            @Override
036            public TypeProjection get(TypeConstructor key) {
037                return null;
038            }
039    
040            @Override
041            public boolean isEmpty() {
042                return false;
043            }
044    
045            @Override
046            public String toString() {
047                return "FunctionDescriptorUtil.MAKE_TYPE_PARAMETERS_FRESH";
048            }
049        });
050    
051        private FunctionDescriptorUtil() {
052        }
053    
054        public static Map<TypeConstructor, TypeProjection> createSubstitutionContext(@NotNull FunctionDescriptor functionDescriptor, List<JetType> typeArguments) {
055            if (functionDescriptor.getTypeParameters().isEmpty()) return Collections.emptyMap();
056    
057            Map<TypeConstructor, TypeProjection> result = new HashMap<TypeConstructor, TypeProjection>();
058    
059            int typeArgumentsSize = typeArguments.size();
060            List<TypeParameterDescriptor> typeParameters = functionDescriptor.getTypeParameters();
061            assert typeArgumentsSize == typeParameters.size();
062            for (int i = 0; i < typeArgumentsSize; i++) {
063                TypeParameterDescriptor typeParameterDescriptor = typeParameters.get(i);
064                JetType typeArgument = typeArguments.get(i);
065                result.put(typeParameterDescriptor.getTypeConstructor(), new TypeProjection(typeArgument));
066            }
067            return result;
068        }
069    
070        @Nullable
071        public static List<ValueParameterDescriptor> getSubstitutedValueParameters(FunctionDescriptor substitutedDescriptor, @NotNull FunctionDescriptor functionDescriptor, @NotNull TypeSubstitutor substitutor) {
072            List<ValueParameterDescriptor> result = new ArrayList<ValueParameterDescriptor>();
073            List<ValueParameterDescriptor> unsubstitutedValueParameters = functionDescriptor.getValueParameters();
074            for (ValueParameterDescriptor unsubstitutedValueParameter : unsubstitutedValueParameters) {
075                // TODO : Lazy?
076                JetType substitutedType = substitutor.substitute(unsubstitutedValueParameter.getType(), Variance.IN_VARIANCE);
077                JetType varargElementType = unsubstitutedValueParameter.getVarargElementType();
078                JetType substituteVarargElementType = varargElementType == null ? null : substitutor.substitute(varargElementType, Variance.IN_VARIANCE);
079                if (substitutedType == null) return null;
080                result.add(new ValueParameterDescriptorImpl(
081                        substitutedDescriptor,
082                        unsubstitutedValueParameter,
083                        unsubstitutedValueParameter.getAnnotations(),
084                        substitutedType,
085                        substituteVarargElementType
086                ));
087            }
088            return result;
089        }
090    
091        @Nullable
092        public static JetType getSubstitutedReturnType(@NotNull FunctionDescriptor functionDescriptor, TypeSubstitutor substitutor) {
093            return substitutor.substitute(functionDescriptor.getReturnType(), Variance.OUT_VARIANCE);
094        }
095    
096        @Nullable
097        public static FunctionDescriptor substituteFunctionDescriptor(@NotNull List<JetType> typeArguments, @NotNull FunctionDescriptor functionDescriptor) {
098            Map<TypeConstructor, TypeProjection> substitutionContext = createSubstitutionContext(functionDescriptor, typeArguments);
099            return functionDescriptor.substitute(TypeSubstitutor.create(substitutionContext));
100        }
101    
102        @NotNull
103        public static JetScope getFunctionInnerScope(@NotNull JetScope outerScope, @NotNull FunctionDescriptor descriptor, @NotNull BindingTrace trace) {
104            WritableScope parameterScope = new WritableScopeImpl(outerScope, descriptor, new TraceBasedRedeclarationHandler(trace), "Function inner scope");
105            ReceiverParameterDescriptor receiver = descriptor.getReceiverParameter();
106            if (receiver != null) {
107                parameterScope.setImplicitReceiver(receiver);
108            }
109            for (TypeParameterDescriptor typeParameter : descriptor.getTypeParameters()) {
110                parameterScope.addTypeParameterDescriptor(typeParameter);
111            }
112            for (ValueParameterDescriptor valueParameterDescriptor : descriptor.getValueParameters()) {
113                parameterScope.addVariableDescriptor(valueParameterDescriptor);
114            }
115            parameterScope.addLabeledDeclaration(descriptor);
116            parameterScope.changeLockLevel(WritableScope.LockLevel.READING);
117            return parameterScope;
118        }
119    
120        public static void initializeFromFunctionType(
121                @NotNull FunctionDescriptorImpl functionDescriptor,
122                @NotNull JetType functionType,
123                @Nullable ReceiverParameterDescriptor expectedThisObject,
124                @NotNull Modality modality,
125                @NotNull Visibility visibility
126        ) {
127    
128            assert KotlinBuiltIns.getInstance().isFunctionOrExtensionFunctionType(functionType);
129            functionDescriptor.initialize(KotlinBuiltIns.getInstance().getReceiverType(functionType),
130                                          expectedThisObject,
131                                          Collections.<TypeParameterDescriptorImpl>emptyList(),
132                                          KotlinBuiltIns.getInstance().getValueParameters(functionDescriptor, functionType),
133                                          KotlinBuiltIns.getInstance().getReturnTypeFromFunctionType(functionType),
134                                          modality,
135                                          visibility);
136        }
137    
138        public static <D extends CallableDescriptor> D alphaConvertTypeParameters(D candidate) {
139            return (D) candidate.substitute(MAKE_TYPE_PARAMETERS_FRESH);
140        }
141    
142        /**
143         * Returns function's copy with new parameter list. Note that parameters may belong to other methods or have incorrect "index" property
144         * -- it will be fixed by this function.
145         */
146        @NotNull
147        public static FunctionDescriptor replaceFunctionParameters(
148                @NotNull FunctionDescriptor function,
149                @NotNull List<ValueParameterDescriptor> newParameters
150        ) {
151            FunctionDescriptorImpl descriptor = new SimpleFunctionDescriptorImpl(
152                    function.getContainingDeclaration(),
153                    function.getAnnotations(),
154                    function.getName(),
155                    function.getKind());
156            List<ValueParameterDescriptor> parameters = new ArrayList<ValueParameterDescriptor>(newParameters.size());
157            int idx = 0;
158            for (ValueParameterDescriptor parameter : newParameters) {
159                JetType returnType = parameter.getReturnType();
160                assert returnType != null;
161    
162                parameters.add(new ValueParameterDescriptorImpl(
163                        descriptor,
164                        idx,
165                        parameter.getAnnotations(),
166                        parameter.getName(),
167                        returnType,
168                        parameter.declaresDefaultValue(),
169                        parameter.getVarargElementType())
170                );
171                idx++;
172            }
173            ReceiverParameterDescriptor receiver = function.getReceiverParameter();
174            descriptor.initialize(
175                    receiver == null ? null : receiver.getType(),
176                    function.getExpectedThisObject(),
177                    function.getTypeParameters(),
178                    parameters,
179                    function.getReturnType(),
180                    function.getModality(),
181                    function.getVisibility());
182            return descriptor;
183        }
184    }