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
017package org.jetbrains.jet.lang.descriptors.impl;
018
019import org.jetbrains.annotations.NotNull;
020import org.jetbrains.annotations.Nullable;
021import org.jetbrains.jet.lang.descriptors.*;
022import org.jetbrains.jet.lang.resolve.BindingTrace;
023import org.jetbrains.jet.lang.resolve.TraceBasedRedeclarationHandler;
024import org.jetbrains.jet.lang.resolve.scopes.JetScope;
025import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
026import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl;
027import org.jetbrains.jet.lang.types.*;
028import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
029
030import java.util.*;
031
032public 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}