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