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 }