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.codegen;
018    
019    import com.google.common.collect.ImmutableMap;
020    import org.jetbrains.annotations.NotNull;
021    import org.jetbrains.annotations.Nullable;
022    import org.jetbrains.jet.lang.descriptors.*;
023    import org.jetbrains.jet.lang.descriptors.impl.MutableClassDescriptor;
024    import org.jetbrains.jet.lang.resolve.java.JvmClassName;
025    import org.jetbrains.jet.lang.resolve.name.Name;
026    import org.jetbrains.jet.lang.resolve.scopes.JetScope;
027    import org.jetbrains.jet.lang.types.JetType;
028    import org.jetbrains.jet.lang.types.JetTypeImpl;
029    import org.jetbrains.jet.lang.types.TypeProjection;
030    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
031    
032    import java.util.ArrayList;
033    import java.util.List;
034    
035    public 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    }