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