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.lang.resolve.java.sam;
018    
019    import com.google.common.collect.Lists;
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.annotations.AnnotationDescriptor;
024    import org.jetbrains.jet.lang.descriptors.impl.ConstructorDescriptorImpl;
025    import org.jetbrains.jet.lang.descriptors.impl.SimpleFunctionDescriptorImpl;
026    import org.jetbrains.jet.lang.descriptors.impl.TypeParameterDescriptorImpl;
027    import org.jetbrains.jet.lang.descriptors.impl.ValueParameterDescriptorImpl;
028    import org.jetbrains.jet.lang.resolve.calls.CallResolverUtil;
029    import org.jetbrains.jet.lang.resolve.java.descriptor.ClassDescriptorFromJvmBytecode;
030    import org.jetbrains.jet.lang.resolve.java.kotlinSignature.SignaturesUtil;
031    import org.jetbrains.jet.lang.resolve.name.Name;
032    import org.jetbrains.jet.lang.types.*;
033    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
034    
035    import java.util.Arrays;
036    import java.util.Collections;
037    import java.util.List;
038    import java.util.Map;
039    
040    import static org.jetbrains.jet.lang.types.Variance.INVARIANT;
041    
042    public class SingleAbstractMethodUtils {
043    
044        @NotNull
045        public static List<CallableMemberDescriptor> getAbstractMembers(@NotNull JetType type) {
046            List<CallableMemberDescriptor> abstractMembers = Lists.newArrayList();
047            for (DeclarationDescriptor member : type.getMemberScope().getAllDescriptors()) {
048                if (member instanceof CallableMemberDescriptor && ((CallableMemberDescriptor) member).getModality() == Modality.ABSTRACT) {
049                    abstractMembers.add((CallableMemberDescriptor) member);
050                }
051            }
052            return abstractMembers;
053        }
054    
055        private static JetType fixProjections(@NotNull JetType functionType) {
056            //removes redundant projection kinds and detects conflicts
057    
058            List<TypeProjection> arguments = Lists.newArrayList();
059            for (TypeParameterDescriptor typeParameter : functionType.getConstructor().getParameters()) {
060                Variance variance = typeParameter.getVariance();
061                TypeProjection argument = functionType.getArguments().get(typeParameter.getIndex());
062                Variance kind = argument.getProjectionKind();
063                if (kind != INVARIANT && variance != INVARIANT) {
064                    if (kind == variance) {
065                        arguments.add(new TypeProjection(argument.getType()));
066                    }
067                    else {
068                        return null;
069                    }
070                }
071                else {
072                     arguments.add(argument);
073                }
074            }
075            ClassifierDescriptor classifier = functionType.getConstructor().getDeclarationDescriptor();
076            assert classifier instanceof ClassDescriptor : "Not class: " + classifier;
077            return new JetTypeImpl(
078                    functionType.getAnnotations(),
079                    functionType.getConstructor(),
080                    functionType.isNullable(),
081                    arguments,
082                    ((ClassDescriptor) classifier).getMemberScope(arguments)
083            );
084        }
085    
086        @Nullable
087        private static JetType getFunctionTypeForSamType(@NotNull JetType samType) {
088            // e.g. samType == Comparator<String>?
089    
090            ClassifierDescriptor classifier = samType.getConstructor().getDeclarationDescriptor();
091            if (classifier instanceof ClassDescriptorFromJvmBytecode) {
092                // Function2<T, T, Int>
093                JetType functionTypeDefault = ((ClassDescriptorFromJvmBytecode) classifier).getFunctionTypeForSamInterface();
094    
095                if (functionTypeDefault != null) {
096                    // Function2<String, String, Int>?
097                    JetType substitute = TypeSubstitutor.create(samType).substitute(functionTypeDefault, Variance.INVARIANT);
098    
099                    return substitute == null ? null : fixProjections(TypeUtils.makeNullableAsSpecified(substitute, samType.isNullable()));
100                }
101            }
102            return null;
103        }
104    
105        @NotNull
106        public static JetType getFunctionTypeForAbstractMethod(@NotNull FunctionDescriptor function) {
107            JetType returnType = function.getReturnType();
108            assert returnType != null : "function is not initialized: " + function;
109            List<JetType> parameterTypes = Lists.newArrayList();
110            for (ValueParameterDescriptor parameter : function.getValueParameters()) {
111                parameterTypes.add(parameter.getType());
112            }
113            return KotlinBuiltIns.getInstance().getFunctionType(
114                    Collections.<AnnotationDescriptor>emptyList(), null, parameterTypes, returnType);
115        }
116    
117        private static boolean isSamInterface(@NotNull ClassDescriptor klass) {
118            if (klass.getKind() != ClassKind.TRAIT) {
119                return false;
120            }
121    
122            List<CallableMemberDescriptor> abstractMembers = getAbstractMembers(klass.getDefaultType());
123            if (abstractMembers.size() == 1) {
124                CallableMemberDescriptor member = abstractMembers.get(0);
125                if (member instanceof SimpleFunctionDescriptor) {
126                    return member.getTypeParameters().isEmpty();
127                }
128            }
129            return false;
130        }
131    
132        @NotNull
133        public static SimpleFunctionDescriptor createSamConstructorFunction(
134                @NotNull ClassOrNamespaceDescriptor owner,
135                @NotNull ClassDescriptor samInterface
136        ) {
137            assert isSamInterface(samInterface) : samInterface;
138    
139            SimpleFunctionDescriptorImpl result = new SimpleFunctionDescriptorImpl(
140                    owner,
141                    samInterface.getAnnotations(),
142                    samInterface.getName(),
143                    CallableMemberDescriptor.Kind.SYNTHESIZED
144            );
145    
146            TypeParameters typeParameters = recreateAndInitializeTypeParameters(samInterface.getTypeConstructor().getParameters(), result);
147    
148            JetType parameterTypeUnsubstituted = getFunctionTypeForSamType(samInterface.getDefaultType());
149            assert parameterTypeUnsubstituted != null : "couldn't get function type for SAM type " + samInterface.getDefaultType();
150            JetType parameterType = typeParameters.substitutor.substitute(parameterTypeUnsubstituted, Variance.IN_VARIANCE);
151            assert parameterType != null : "couldn't substitute type: " + parameterType + ", substitutor = " + typeParameters.substitutor;
152            ValueParameterDescriptor parameter = new ValueParameterDescriptorImpl(
153                    result, 0, Collections.<AnnotationDescriptor>emptyList(), Name.identifier("function"), parameterType, false, null);
154    
155            JetType returnType = typeParameters.substitutor.substitute(samInterface.getDefaultType(), Variance.OUT_VARIANCE);
156            assert returnType != null : "couldn't substitute type: " + returnType + ", substitutor = " + typeParameters.substitutor;
157    
158            result.initialize(
159                    null,
160                    null,
161                    typeParameters.descriptors,
162                    Arrays.asList(parameter),
163                    returnType,
164                    Modality.FINAL,
165                    samInterface.getVisibility(),
166                    false
167            );
168    
169            return result;
170        }
171    
172        public static boolean isSamType(@NotNull JetType type) {
173            return getFunctionTypeForSamType(type) != null;
174        }
175    
176        public static boolean isSamAdapterNecessary(@NotNull FunctionDescriptor fun) {
177            for (ValueParameterDescriptor param : fun.getValueParameters()) {
178                if (isSamType(param.getType())) {
179                    return true;
180                }
181            }
182            return false;
183        }
184    
185        @NotNull
186        public static SimpleFunctionDescriptor createSamAdapterFunction(@NotNull final SimpleFunctionDescriptor original) {
187            final SimpleFunctionDescriptorImpl result = new SimpleFunctionDescriptorImpl(
188                    original.getContainingDeclaration(),
189                    original.getAnnotations(),
190                    original.getName(),
191                    CallableMemberDescriptor.Kind.SYNTHESIZED,
192                    original
193            );
194            FunctionInitializer initializer = new FunctionInitializer() {
195                @Override
196                public void initialize(
197                        @NotNull List<TypeParameterDescriptor> typeParameters,
198                        @NotNull List<ValueParameterDescriptor> valueParameters,
199                        @Nullable JetType returnType
200                ) {
201                    result.initialize(
202                            null,
203                            original.getExpectedThisObject(),
204                            typeParameters,
205                            valueParameters,
206                            returnType,
207                            Modality.FINAL,
208                            original.getVisibility(),
209                            false
210                    );
211                }
212            };
213            return initSamAdapter(original, result, initializer);
214        }
215    
216        @NotNull
217        public static ConstructorDescriptor createSamAdapterConstructor(@NotNull final ConstructorDescriptor original) {
218            final ConstructorDescriptorImpl result = new ConstructorDescriptorImpl(
219                    original.getContainingDeclaration(),
220                    original.getAnnotations(),
221                    original.isPrimary(),
222                    CallableMemberDescriptor.Kind.SYNTHESIZED
223            );
224            FunctionInitializer initializer = new FunctionInitializer() {
225                @Override
226                public void initialize(
227                        @NotNull List<TypeParameterDescriptor> typeParameters,
228                        @NotNull List<ValueParameterDescriptor> valueParameters,
229                        @Nullable JetType returnType
230                ) {
231                    result.initialize(
232                            typeParameters,
233                            valueParameters,
234                            original.getVisibility(),
235                            original.getExpectedThisObject() == ReceiverParameterDescriptor.NO_RECEIVER_PARAMETER
236                    );
237                }
238            };
239            return initSamAdapter(original, result, initializer);
240        }
241    
242        private static <F extends FunctionDescriptor> F initSamAdapter(
243                @NotNull F original,
244                @NotNull F adapter,
245                @NotNull FunctionInitializer initializer
246        ) {
247            TypeParameters typeParameters = recreateAndInitializeTypeParameters(original.getTypeParameters(), adapter);
248    
249            JetType returnTypeUnsubstituted = original.getReturnType();
250            JetType returnType;
251            if (returnTypeUnsubstituted == null) { // return type may be null for not yet initialized constructors
252                returnType = null;
253            }
254            else {
255                returnType = typeParameters.substitutor.substitute(returnTypeUnsubstituted, Variance.OUT_VARIANCE);
256                assert returnType != null : "couldn't substitute type: " + returnType + ", substitutor = " + typeParameters.substitutor;
257            }
258    
259            List<ValueParameterDescriptor> valueParameters = Lists.newArrayList();
260            for (ValueParameterDescriptor originalParam : original.getValueParameters()) {
261                JetType originalType = originalParam.getType();
262                JetType functionType = getFunctionTypeForSamType(originalType);
263                JetType newTypeUnsubstituted = functionType != null ? functionType : originalType;
264                JetType newType = typeParameters.substitutor.substitute(newTypeUnsubstituted, Variance.IN_VARIANCE);
265                assert newType != null : "couldn't substitute type: " + newTypeUnsubstituted + ", substitutor = " + typeParameters.substitutor;
266    
267                ValueParameterDescriptor newParam = new ValueParameterDescriptorImpl(
268                        adapter, originalParam.getIndex(), originalParam.getAnnotations(), originalParam.getName(), newType, false, null);
269                valueParameters.add(newParam);
270            }
271    
272            initializer.initialize(typeParameters.descriptors, valueParameters, returnType);
273            return adapter;
274        }
275    
276        @NotNull
277        private static TypeParameters recreateAndInitializeTypeParameters(
278                @NotNull List<TypeParameterDescriptor> originalParameters,
279                @Nullable DeclarationDescriptor newOwner
280        ) {
281            Map<TypeParameterDescriptor, TypeParameterDescriptorImpl> traitToFunTypeParameters =
282                    SignaturesUtil.recreateTypeParametersAndReturnMapping(originalParameters, newOwner);
283            TypeSubstitutor typeParametersSubstitutor = SignaturesUtil.createSubstitutorForTypeParameters(traitToFunTypeParameters);
284            for (Map.Entry<TypeParameterDescriptor, TypeParameterDescriptorImpl> mapEntry : traitToFunTypeParameters.entrySet()) {
285                TypeParameterDescriptor traitTypeParameter = mapEntry.getKey();
286                TypeParameterDescriptorImpl funTypeParameter = mapEntry.getValue();
287    
288                for (JetType upperBound : traitTypeParameter.getUpperBounds()) {
289                    JetType upperBoundSubstituted = typeParametersSubstitutor.substitute(upperBound, Variance.INVARIANT);
290                    assert upperBoundSubstituted != null : "couldn't substitute type: " + upperBound + ", substitutor = " + typeParametersSubstitutor;
291                    funTypeParameter.addUpperBound(upperBoundSubstituted);
292                }
293    
294                funTypeParameter.setInitialized();
295            }
296    
297            List<TypeParameterDescriptor> typeParameters = Lists.<TypeParameterDescriptor>newArrayList(traitToFunTypeParameters.values());
298            return new TypeParameters(typeParameters, typeParametersSubstitutor);
299        }
300    
301        @NotNull
302        public static SimpleFunctionDescriptor getAbstractMethodOfSamType(@NotNull JetType type) {
303            return (SimpleFunctionDescriptor) getAbstractMembers(type).get(0);
304        }
305    
306        @NotNull
307        public static SimpleFunctionDescriptor getAbstractMethodOfSamInterface(@NotNull ClassDescriptor samInterface) {
308            return getAbstractMethodOfSamType(samInterface.getDefaultType());
309        }
310    
311        private SingleAbstractMethodUtils() {
312        }
313    
314        private static class TypeParameters {
315            public final List<TypeParameterDescriptor> descriptors;
316            public final TypeSubstitutor substitutor;
317    
318            private TypeParameters(List<TypeParameterDescriptor> descriptors, TypeSubstitutor substitutor) {
319                this.descriptors = descriptors;
320                this.substitutor = substitutor;
321            }
322        }
323    
324        private static abstract class FunctionInitializer {
325            public abstract void initialize(
326                    @NotNull List<TypeParameterDescriptor> typeParameters,
327                    @NotNull List<ValueParameterDescriptor> valueParameters,
328                    @Nullable JetType returnType
329            );
330        }
331    }