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.codegen;
018
019import com.google.common.collect.ImmutableMap;
020import org.jetbrains.annotations.NotNull;
021import org.jetbrains.annotations.Nullable;
022import org.jetbrains.jet.lang.descriptors.*;
023import org.jetbrains.jet.lang.descriptors.impl.MutableClassDescriptor;
024import org.jetbrains.jet.lang.resolve.java.JvmClassName;
025import org.jetbrains.jet.lang.resolve.name.Name;
026import org.jetbrains.jet.lang.resolve.scopes.JetScope;
027import org.jetbrains.jet.lang.types.JetType;
028import org.jetbrains.jet.lang.types.JetTypeImpl;
029import org.jetbrains.jet.lang.types.TypeProjection;
030import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
031
032import java.util.ArrayList;
033import java.util.List;
034
035public class FunctionTypesUtil {
036    private static final List<ClassDescriptor> FUNCTIONS;
037    private static final List<ClassDescriptor> EXTENSION_FUNCTIONS;
038    private static final List<ClassDescriptor> K_FUNCTIONS;
039    private static final List<ClassDescriptor> K_MEMBER_FUNCTIONS;
040    private static final List<ClassDescriptor> K_EXTENSION_FUNCTIONS;
041
042    private static final ImmutableMap<ClassDescriptor, ClassDescriptor> FUNCTION_TO_IMPL;
043
044    static {
045        int n = KotlinBuiltIns.FUNCTION_TRAIT_COUNT;
046        FUNCTIONS = new ArrayList<ClassDescriptor>(n);
047        EXTENSION_FUNCTIONS = new ArrayList<ClassDescriptor>(n);
048        K_FUNCTIONS = new ArrayList<ClassDescriptor>(n);
049        K_MEMBER_FUNCTIONS = new ArrayList<ClassDescriptor>(n);
050        K_EXTENSION_FUNCTIONS = new ArrayList<ClassDescriptor>(n);
051
052        KotlinBuiltIns builtIns = KotlinBuiltIns.getInstance();
053        for (int i = 0; i < n; i++) {
054            Name functionImpl = Name.identifier("FunctionImpl" + i);
055            FUNCTIONS.add(createFunctionImplDescriptor(functionImpl, builtIns.getFunction(i)));
056
057            Name extensionFunctionImpl = Name.identifier("ExtensionFunctionImpl" + i);
058            EXTENSION_FUNCTIONS.add(createFunctionImplDescriptor(extensionFunctionImpl, builtIns.getExtensionFunction(i)));
059
060            Name kFunctionImpl = Name.identifier("KFunctionImpl" + i);
061            K_FUNCTIONS.add(createFunctionImplDescriptor(kFunctionImpl, builtIns.getKFunction(i)));
062
063            Name kMemberFunctionImpl = Name.identifier("KMemberFunctionImpl" + i);
064            K_MEMBER_FUNCTIONS.add(createFunctionImplDescriptor(kMemberFunctionImpl, builtIns.getKMemberFunction(i)));
065
066            Name kExtensionFunctionImpl = Name.identifier("KExtensionFunctionImpl" + i);
067            K_EXTENSION_FUNCTIONS.add(createFunctionImplDescriptor(kExtensionFunctionImpl, builtIns.getKExtensionFunction(i)));
068        }
069
070        ImmutableMap.Builder<ClassDescriptor, ClassDescriptor> builder = ImmutableMap.builder();
071        for (int i = 0; i < n; i++) {
072            builder.put(builtIns.getKFunction(i), K_FUNCTIONS.get(i));
073            builder.put(builtIns.getKMemberFunction(i), K_MEMBER_FUNCTIONS.get(i));
074            builder.put(builtIns.getKExtensionFunction(i), K_EXTENSION_FUNCTIONS.get(i));
075        }
076        FUNCTION_TO_IMPL = builder.build();
077    }
078
079    private FunctionTypesUtil() {
080    }
081
082
083    @Nullable
084    public static ClassDescriptor functionTypeToImpl(@NotNull JetType functionType) {
085        //noinspection SuspiciousMethodCalls
086        return FUNCTION_TO_IMPL.get(functionType.getConstructor().getDeclarationDescriptor());
087    }
088
089    @NotNull
090    public static JetType getSuperTypeForClosure(@NotNull FunctionDescriptor descriptor, boolean kFunction) {
091        int arity = descriptor.getValueParameters().size();
092
093        ReceiverParameterDescriptor receiverParameter = descriptor.getReceiverParameter();
094        ReceiverParameterDescriptor expectedThisObject = descriptor.getExpectedThisObject();
095
096        List<TypeProjection> typeArguments = new ArrayList<TypeProjection>(arity + 2);
097        if (receiverParameter != null) {
098            typeArguments.add(new TypeProjection(receiverParameter.getType()));
099        }
100        else if (kFunction && expectedThisObject != null) {
101            typeArguments.add(new TypeProjection(expectedThisObject.getType()));
102        }
103
104        for (ValueParameterDescriptor parameter : descriptor.getValueParameters()) {
105            typeArguments.add(new TypeProjection(parameter.getType()));
106        }
107
108        typeArguments.add(new TypeProjection(descriptor.getReturnType()));
109
110        ClassDescriptor classDescriptor;
111        if (kFunction) {
112            if (expectedThisObject != null) {
113                classDescriptor = K_MEMBER_FUNCTIONS.get(arity);
114            }
115            else if (receiverParameter != null) {
116                classDescriptor = K_EXTENSION_FUNCTIONS.get(arity);
117            }
118            else {
119                classDescriptor = K_FUNCTIONS.get(arity);
120            }
121        }
122        else {
123            if (receiverParameter != null) {
124                classDescriptor = EXTENSION_FUNCTIONS.get(arity);
125            }
126            else {
127                classDescriptor = FUNCTIONS.get(arity);
128            }
129        }
130
131        return new JetTypeImpl(
132                classDescriptor.getDefaultType().getAnnotations(),
133                classDescriptor.getTypeConstructor(),
134                false,
135                typeArguments,
136                classDescriptor.getMemberScope(typeArguments)
137        );
138    }
139
140    @NotNull
141    private static ClassDescriptor createFunctionImplDescriptor(@NotNull Name name, @NotNull ClassDescriptor functionInterface) {
142        JetScope builtInsScope = KotlinBuiltIns.getInstance().getBuiltInsScope();
143
144        MutableClassDescriptor functionImpl = new MutableClassDescriptor(
145                builtInsScope.getContainingDeclaration(),
146                builtInsScope,
147                ClassKind.CLASS,
148                false,
149                name
150        );
151        functionImpl.setModality(Modality.FINAL);
152        functionImpl.setVisibility(Visibilities.PUBLIC);
153        functionImpl.setTypeParameterDescriptors(functionInterface.getDefaultType().getConstructor().getParameters());
154        functionImpl.createTypeConstructor();
155
156        return functionImpl;
157    }
158
159    @NotNull
160    public static JvmClassName getFunctionTraitClassName(@NotNull FunctionDescriptor descriptor) {
161        int paramCount = descriptor.getValueParameters().size();
162        if (descriptor.getReceiverParameter() != null) {
163            return JvmClassName.byInternalName("jet/ExtensionFunction" + paramCount);
164        }
165        else {
166            return JvmClassName.byInternalName("jet/Function" + paramCount);
167        }
168    }
169
170    @NotNull
171    public static JvmClassName getFunctionImplClassName(@NotNull FunctionDescriptor descriptor) {
172        int paramCount = descriptor.getValueParameters().size();
173        if (descriptor.getReceiverParameter() != null) {
174            return JvmClassName.byInternalName("jet/ExtensionFunctionImpl" + paramCount);
175        }
176        else {
177            return JvmClassName.byInternalName("jet/FunctionImpl" + paramCount);
178        }
179    }
180}