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