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.ImmutableList;
020    import com.google.common.collect.ImmutableMap;
021    import org.jetbrains.annotations.NotNull;
022    import org.jetbrains.annotations.Nullable;
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.reflect.ReflectionTypes;
027    import org.jetbrains.jet.lang.resolve.ImportPath;
028    import org.jetbrains.jet.lang.resolve.java.mapping.JavaToKotlinClassMap;
029    import org.jetbrains.jet.lang.resolve.name.FqName;
030    import org.jetbrains.jet.lang.resolve.name.Name;
031    import org.jetbrains.jet.lang.types.JetType;
032    import org.jetbrains.jet.lang.types.JetTypeImpl;
033    import org.jetbrains.jet.lang.types.TypeProjection;
034    import org.jetbrains.jet.lang.types.TypeProjectionImpl;
035    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
036    
037    import java.util.ArrayList;
038    import java.util.Collections;
039    import java.util.List;
040    import java.util.Map;
041    
042    public class JvmFunctionImplTypes {
043        private final ReflectionTypes reflectionTypes;
044        private final ModuleDescriptor fakeModule;
045    
046        private volatile List<Functions> functionsList;
047        private volatile List<KFunctions> kFunctionsList;
048        private volatile Map<ClassDescriptor, ClassDescriptor> kFunctionToImplMap;
049    
050        private static class Functions {
051            public final ClassDescriptor functionImpl;
052            public final ClassDescriptor extensionFunctionImpl;
053    
054            public Functions(
055                    @NotNull ClassDescriptor functionImpl,
056                    @NotNull ClassDescriptor extensionFunctionImpl
057            ) {
058                this.functionImpl = functionImpl;
059                this.extensionFunctionImpl = extensionFunctionImpl;
060            }
061        }
062    
063        private static class KFunctions {
064            public final ClassDescriptor kFunctionImpl;
065            public final ClassDescriptor kMemberFunctionImpl;
066            public final ClassDescriptor kExtensionFunctionImpl;
067    
068            public KFunctions(
069                    @NotNull ClassDescriptor kFunctionImpl,
070                    @NotNull ClassDescriptor kMemberFunctionImpl,
071                    @NotNull ClassDescriptor kExtensionFunctionImpl
072            ) {
073                this.kFunctionImpl = kFunctionImpl;
074                this.kMemberFunctionImpl = kMemberFunctionImpl;
075                this.kExtensionFunctionImpl = kExtensionFunctionImpl;
076            }
077        }
078    
079        public JvmFunctionImplTypes(@NotNull ReflectionTypes reflectionTypes) {
080            this.reflectionTypes = reflectionTypes;
081            this.fakeModule = new ModuleDescriptorImpl(Name.special("<fake module for functions impl>"), Collections.<ImportPath>emptyList(),
082                                                       JavaToKotlinClassMap.getInstance());
083        }
084    
085        @NotNull
086        private List<Functions> getFunctionsImplList() {
087            if (functionsList == null) {
088                MutablePackageFragmentDescriptor kotlin = new MutablePackageFragmentDescriptor(fakeModule, new FqName("kotlin"));
089                KotlinBuiltIns builtIns = KotlinBuiltIns.getInstance();
090    
091                ImmutableList.Builder<Functions> builder = ImmutableList.builder();
092                for (int i = 0; i < KotlinBuiltIns.FUNCTION_TRAIT_COUNT; i++) {
093                    builder.add(new Functions(
094                            createFunctionImpl(kotlin, "FunctionImpl" + i, builtIns.getFunction(i)),
095                            createFunctionImpl(kotlin, "ExtensionFunctionImpl" + i, builtIns.getExtensionFunction(i))
096                    ));
097                }
098                functionsList = builder.build();
099            }
100            return functionsList;
101        }
102    
103        @NotNull
104        private List<KFunctions> getKFunctionsImplList() {
105            if (kFunctionsList == null) {
106                MutablePackageFragmentDescriptor reflect = new MutablePackageFragmentDescriptor(fakeModule, new FqName("kotlin.reflect"));
107    
108                ImmutableList.Builder<KFunctions> builder = ImmutableList.builder();
109                for (int i = 0; i < KotlinBuiltIns.FUNCTION_TRAIT_COUNT; i++) {
110                    builder.add(new KFunctions(
111                            createFunctionImpl(reflect, "KFunctionImpl" + i, reflectionTypes.getKFunction(i)),
112                            createFunctionImpl(reflect, "KMemberFunctionImpl" + i, reflectionTypes.getKMemberFunction(i)),
113                            createFunctionImpl(reflect, "KExtensionFunctionImpl" + i, reflectionTypes.getKExtensionFunction(i))
114                    ));
115                }
116                kFunctionsList = builder.build();
117            }
118            return kFunctionsList;
119        }
120    
121        @NotNull
122        private Map<ClassDescriptor, ClassDescriptor> getKFunctionToImplMap() {
123            if (kFunctionToImplMap == null) {
124                ImmutableMap.Builder<ClassDescriptor, ClassDescriptor> builder = ImmutableMap.builder();
125                for (int i = 0; i < KotlinBuiltIns.FUNCTION_TRAIT_COUNT; i++) {
126                    KFunctions kFunctions = getKFunctionsImplList().get(i);
127                    builder.put(reflectionTypes.getKFunction(i), kFunctions.kFunctionImpl);
128                    builder.put(reflectionTypes.getKMemberFunction(i), kFunctions.kMemberFunctionImpl);
129                    builder.put(reflectionTypes.getKExtensionFunction(i), kFunctions.kExtensionFunctionImpl);
130                }
131                kFunctionToImplMap = builder.build();
132            }
133            return kFunctionToImplMap;
134        }
135    
136    
137        @Nullable
138        public ClassDescriptor kFunctionTypeToImpl(@NotNull JetType functionType) {
139            //noinspection SuspiciousMethodCalls
140            return getKFunctionToImplMap().get(functionType.getConstructor().getDeclarationDescriptor());
141        }
142    
143        @NotNull
144        public JetType getSuperTypeForClosure(@NotNull FunctionDescriptor descriptor, boolean kFunction) {
145            int arity = descriptor.getValueParameters().size();
146    
147            ReceiverParameterDescriptor receiverParameter = descriptor.getReceiverParameter();
148            ReceiverParameterDescriptor expectedThisObject = descriptor.getExpectedThisObject();
149    
150            List<TypeProjection> typeArguments = new ArrayList<TypeProjection>(arity + 2);
151            if (receiverParameter != null) {
152                typeArguments.add(new TypeProjectionImpl(receiverParameter.getType()));
153            }
154            else if (kFunction && expectedThisObject != null) {
155                typeArguments.add(new TypeProjectionImpl(expectedThisObject.getType()));
156            }
157    
158            for (ValueParameterDescriptor parameter : descriptor.getValueParameters()) {
159                typeArguments.add(new TypeProjectionImpl(parameter.getType()));
160            }
161    
162            //noinspection ConstantConditions
163            typeArguments.add(new TypeProjectionImpl(descriptor.getReturnType()));
164    
165            ClassDescriptor classDescriptor;
166            if (kFunction) {
167                KFunctions kFunctions = getKFunctionsImplList().get(arity);
168                if (expectedThisObject != null) {
169                    classDescriptor = kFunctions.kMemberFunctionImpl;
170                }
171                else if (receiverParameter != null) {
172                    classDescriptor = kFunctions.kExtensionFunctionImpl;
173                }
174                else {
175                    classDescriptor = kFunctions.kFunctionImpl;
176                }
177            }
178            else {
179                Functions functions = getFunctionsImplList().get(arity);
180                if (receiverParameter != null) {
181                    classDescriptor = functions.extensionFunctionImpl;
182                }
183                else {
184                    classDescriptor = functions.functionImpl;
185                }
186            }
187    
188            return new JetTypeImpl(
189                    classDescriptor.getDefaultType().getAnnotations(),
190                    classDescriptor.getTypeConstructor(),
191                    false,
192                    typeArguments,
193                    classDescriptor.getMemberScope(typeArguments)
194            );
195        }
196    
197        @NotNull
198        private static ClassDescriptor createFunctionImpl(
199                @NotNull PackageFragmentDescriptor containingDeclaration,
200                @NotNull String name,
201                @NotNull ClassDescriptor functionInterface
202        ) {
203            MutableClassDescriptor functionImpl = new MutableClassDescriptor(
204                    containingDeclaration,
205                    containingDeclaration.getMemberScope(),
206                    ClassKind.CLASS,
207                    false,
208                    Name.identifier(name)
209            );
210            functionImpl.setModality(Modality.FINAL);
211            functionImpl.setVisibility(Visibilities.PUBLIC);
212            functionImpl.setTypeParameterDescriptors(functionInterface.getDefaultType().getConstructor().getParameters());
213            functionImpl.createTypeConstructor();
214    
215            return functionImpl;
216        }
217    }