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.kotlinSignature;
018    
019    import com.google.common.collect.*;
020    import com.intellij.openapi.diagnostic.Logger;
021    import com.intellij.openapi.util.Pair;
022    import com.intellij.openapi.util.SystemInfo;
023    import com.intellij.psi.PsiElement;
024    import com.intellij.psi.PsiManager;
025    import com.intellij.psi.PsiMethod;
026    import com.intellij.util.Function;
027    import com.intellij.util.containers.ContainerUtil;
028    import kotlin.Function1;
029    import kotlin.KotlinPackage;
030    import org.jetbrains.annotations.NotNull;
031    import org.jetbrains.annotations.Nullable;
032    import org.jetbrains.jet.lang.descriptors.*;
033    import org.jetbrains.jet.lang.descriptors.impl.TypeParameterDescriptorImpl;
034    import org.jetbrains.jet.lang.descriptors.impl.ValueParameterDescriptorImpl;
035    import org.jetbrains.jet.lang.resolve.BindingContext;
036    import org.jetbrains.jet.lang.resolve.BindingContextUtils;
037    import org.jetbrains.jet.lang.resolve.BindingTrace;
038    import org.jetbrains.jet.lang.resolve.DescriptorUtils;
039    import org.jetbrains.jet.lang.resolve.java.jetAsJava.KotlinLightMethod;
040    import org.jetbrains.jet.lang.resolve.java.mapping.JavaToKotlinClassMap;
041    import org.jetbrains.jet.lang.resolve.java.resolver.DescriptorResolverUtils;
042    import org.jetbrains.jet.lang.resolve.java.resolver.TypeUsage;
043    import org.jetbrains.jet.lang.resolve.java.structure.JavaClass;
044    import org.jetbrains.jet.lang.resolve.java.structure.JavaMethod;
045    import org.jetbrains.jet.lang.resolve.java.structure.impl.JavaMethodImpl;
046    import org.jetbrains.jet.lang.resolve.name.FqName;
047    import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe;
048    import org.jetbrains.jet.lang.resolve.name.Name;
049    import org.jetbrains.jet.lang.resolve.scopes.JetScope;
050    import org.jetbrains.jet.lang.types.*;
051    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
052    import org.jetbrains.jet.renderer.DescriptorRenderer;
053    
054    import java.util.*;
055    
056    import static org.jetbrains.jet.lang.resolve.DescriptorUtils.getFqName;
057    import static org.jetbrains.jet.lang.resolve.java.resolver.TypeUsage.*;
058    import static org.jetbrains.jet.lang.types.Variance.INVARIANT;
059    
060    public class SignaturesPropagationData {
061        private static final Logger LOG = Logger.getInstance(SignaturesPropagationData.class);
062    
063        private final List<TypeParameterDescriptor> modifiedTypeParameters;
064        private final ValueParameters modifiedValueParameters;
065        private final JetType modifiedReturnType;
066    
067        private final List<String> signatureErrors = Lists.newArrayList();
068        private final List<FunctionDescriptor> superFunctions;
069        private final Map<TypeParameterDescriptor, TypeParameterDescriptorImpl> autoTypeParameterToModified;
070        final ClassDescriptor containingClass;
071    
072        public SignaturesPropagationData(
073                @NotNull ClassDescriptor containingClass,
074                @NotNull JetType autoReturnType, // type built by JavaTypeTransformer from Java signature and @NotNull annotations
075                @Nullable JetType receiverType,
076                @NotNull List<ValueParameterDescriptor> autoValueParameters, // descriptors built by parameters resolver
077                @NotNull List<TypeParameterDescriptor> autoTypeParameters, // descriptors built by signature resolver
078                @NotNull JavaMethodImpl method,
079                @NotNull BindingTrace trace
080        ) {
081            this.containingClass = containingClass;
082            superFunctions = getSuperFunctionsForMethod(method, trace, containingClass);
083    
084            autoTypeParameterToModified = DescriptorResolverUtils.recreateTypeParametersAndReturnMapping(autoTypeParameters, null);
085    
086            modifiedTypeParameters = modifyTypeParametersAccordingToSuperMethods(autoTypeParameters);
087            modifiedReturnType = modifyReturnTypeAccordingToSuperMethods(autoReturnType);
088            modifiedValueParameters = modifyValueParametersAccordingToSuperMethods(receiverType, autoValueParameters);
089        }
090    
091        public List<TypeParameterDescriptor> getModifiedTypeParameters() {
092            return modifiedTypeParameters;
093        }
094    
095        public JetType getModifiedReceiverType() {
096            return modifiedValueParameters.receiverType;
097        }
098    
099        public List<ValueParameterDescriptor> getModifiedValueParameters() {
100            return modifiedValueParameters.descriptors;
101        }
102    
103        public boolean getModifiedHasStableParameterNames() {
104            return modifiedValueParameters.hasStableParameterNames;
105        }
106    
107        public JetType getModifiedReturnType() {
108            return modifiedReturnType;
109        }
110    
111        public List<String> getSignatureErrors() {
112            return signatureErrors;
113        }
114    
115        public List<FunctionDescriptor> getSuperFunctions() {
116            return superFunctions;
117        }
118    
119        void reportError(String error) {
120            signatureErrors.add(error);
121        }
122    
123        private JetType modifyReturnTypeAccordingToSuperMethods(
124                @NotNull JetType autoType // type built by JavaTypeTransformer
125        ) {
126            List<TypeAndVariance> typesFromSuperMethods = ContainerUtil.map(superFunctions,
127                    new Function<FunctionDescriptor, TypeAndVariance>() {
128                        @Override
129                        public TypeAndVariance fun(FunctionDescriptor superFunction) {
130                            return new TypeAndVariance(superFunction.getReturnType(), Variance.OUT_VARIANCE);
131                        }
132                    });
133    
134            return modifyTypeAccordingToSuperMethods(autoType, typesFromSuperMethods, MEMBER_SIGNATURE_COVARIANT);
135        }
136    
137        private List<TypeParameterDescriptor> modifyTypeParametersAccordingToSuperMethods(List<TypeParameterDescriptor> autoTypeParameters) {
138            List<TypeParameterDescriptor> result = Lists.newArrayList();
139    
140            for (TypeParameterDescriptor autoParameter : autoTypeParameters) {
141                int index = autoParameter.getIndex();
142                TypeParameterDescriptorImpl modifiedTypeParameter = autoTypeParameterToModified.get(autoParameter);
143    
144                List<Iterator<JetType>> upperBoundFromSuperFunctionsIterators = Lists.newArrayList();
145                for (FunctionDescriptor superFunction : superFunctions) {
146                    upperBoundFromSuperFunctionsIterators.add(superFunction.getTypeParameters().get(index).getUpperBounds().iterator());
147                }
148    
149                for (JetType autoUpperBound : autoParameter.getUpperBounds()) {
150                    List<TypeAndVariance> upperBoundsFromSuperFunctions = Lists.newArrayList();
151    
152                    for (Iterator<JetType> iterator : upperBoundFromSuperFunctionsIterators) {
153                        assert iterator.hasNext();
154                        upperBoundsFromSuperFunctions.add(new TypeAndVariance(iterator.next(), INVARIANT));
155                    }
156    
157                    JetType modifiedUpperBound = modifyTypeAccordingToSuperMethods(autoUpperBound, upperBoundsFromSuperFunctions, UPPER_BOUND);
158                    modifiedTypeParameter.addUpperBound(modifiedUpperBound);
159                }
160    
161                for (Iterator<JetType> iterator : upperBoundFromSuperFunctionsIterators) {
162                    assert !iterator.hasNext();
163                }
164    
165                modifiedTypeParameter.setInitialized();
166                result.add(modifiedTypeParameter);
167            }
168    
169            return result;
170        }
171    
172        private ValueParameters modifyValueParametersAccordingToSuperMethods(
173                @Nullable JetType receiverType,
174                @NotNull List<ValueParameterDescriptor> parameters // descriptors built by parameters resolver
175        ) {
176            assert receiverType == null : "Parameters before propagation have receiver type," +
177                                          " but propagation should be disabled for functions compiled from Kotlin in class: " +
178                                          DescriptorUtils.getFqName(containingClass);
179    
180            JetType resultReceiverType = null;
181            List<ValueParameterDescriptor> resultParameters = Lists.newArrayList();
182    
183            boolean shouldBeExtension = checkIfShouldBeExtension();
184    
185            for (final ValueParameterDescriptor originalParam : parameters) {
186                final int originalIndex = originalParam.getIndex();
187                List<TypeAndName> typesFromSuperMethods = ContainerUtil.map(superFunctions,
188                        new Function<FunctionDescriptor, TypeAndName>() {
189                            @Override
190                            public TypeAndName fun(FunctionDescriptor superFunction) {
191                                ReceiverParameterDescriptor receiver = superFunction.getReceiverParameter();
192                                int index = receiver != null ? originalIndex - 1 : originalIndex;
193                                if (index == -1) {
194                                    assert receiver != null : "can't happen: index is -1, while function is not extension";
195                                    return new TypeAndName(receiver.getType(), originalParam.getName());
196                                }
197                                ValueParameterDescriptor parameter = superFunction.getValueParameters().get(index);
198                                return new TypeAndName(parameter.getType(), parameter.getName());
199                            }
200                        });
201    
202                VarargCheckResult varargCheckResult = checkVarargInSuperFunctions(originalParam);
203    
204                JetType altType = modifyTypeAccordingToSuperMethods(varargCheckResult.parameterType,
205                                                                    convertToTypeVarianceList(typesFromSuperMethods),
206                                                                    MEMBER_SIGNATURE_CONTRAVARIANT);
207    
208                if (shouldBeExtension && originalIndex == 0) {
209                    resultReceiverType = altType;
210                }
211                else {
212                    Name stableName = null;
213                    for (int i = 0; i < superFunctions.size(); i++) {
214                        if (superFunctions.get(i).hasStableParameterNames()) {
215                            // When there's more than one stable name in super functions, we pick the first one. This behaviour is similar to
216                            // the compiler front-end, except that it reports a warning in such cases
217                            // TODO: report a warning somewhere if there's more than one stable name in super functions
218                            stableName = typesFromSuperMethods.get(i).name;
219                            break;
220                        }
221                    }
222    
223                    resultParameters.add(new ValueParameterDescriptorImpl(
224                            originalParam.getContainingDeclaration(),
225                            shouldBeExtension ? originalIndex - 1 : originalIndex,
226                            originalParam.getAnnotations(),
227                            stableName != null ? stableName : originalParam.getName(),
228                            altType,
229                            originalParam.declaresDefaultValue(),
230                            varargCheckResult.isVararg ? KotlinBuiltIns.getInstance().getArrayElementType(altType) : null
231                    ));
232                }
233            }
234    
235            boolean hasStableParameterNames = KotlinPackage.any(superFunctions, new Function1<FunctionDescriptor, Boolean>() {
236                @Override
237                public Boolean invoke(FunctionDescriptor descriptor) {
238                    return descriptor.hasStableParameterNames();
239                }
240            });
241    
242            return new ValueParameters(resultReceiverType, resultParameters, hasStableParameterNames);
243        }
244    
245        @NotNull
246        private static List<TypeAndVariance> convertToTypeVarianceList(@NotNull List<TypeAndName> list) {
247            return KotlinPackage.map(list, new Function1<TypeAndName, TypeAndVariance>() {
248                @Override
249                public TypeAndVariance invoke(TypeAndName tvn) {
250                    return new TypeAndVariance(tvn.type, INVARIANT);
251                }
252            });
253        }
254    
255        private static List<FunctionDescriptor> getSuperFunctionsForMethod(
256                @NotNull JavaMethodImpl method,
257                @NotNull BindingTrace trace,
258                @NotNull ClassDescriptor containingClass
259        ) {
260            List<FunctionDescriptor> superFunctions = Lists.newArrayList();
261    
262            Map<ClassDescriptor, JetType> superclassToSupertype = getSuperclassToSupertypeMap(containingClass);
263    
264            Multimap<FqName, Pair<FunctionDescriptor, JavaMethodImpl>> superclassToFunctions =
265                    getSuperclassToFunctionsMultimap(method, trace.getBindingContext(), containingClass);
266    
267            for (JavaMethodImpl superMethod : PropagationHeuristics.getSuperMethods(method)) {
268                JavaClass javaClass = superMethod.getContainingClass();
269                FqName classFqName = javaClass.getFqName();
270                assert classFqName != null : "Class FQ name should not be null: " + javaClass;
271    
272                if (!JavaToKotlinClassMap.getInstance().mapPlatformClass(classFqName).isEmpty()) {
273                    for (FunctionDescriptor superFun : JavaToKotlinMethodMap.INSTANCE.getFunctions(superMethod, classFqName, containingClass)) {
274                        superFunctions.add(substituteSuperFunction(superclassToSupertype, superFun));
275                    }
276                    continue;
277                }
278    
279                DeclarationDescriptor superFun = superMethod.getPsi() instanceof KotlinLightMethod
280                                                 ? trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, ((KotlinLightMethod) superMethod.getPsi()).getOrigin())
281                                                 : findSuperFunction(superclassToFunctions.get(classFqName), superMethod);
282                if (superFun == null) {
283                    // Super methods which are Object methods in interfaces are not loaded by JDR.
284                    if (!DescriptorResolverUtils.isObjectMethodInInterface(superMethod)) {
285                        reportCantFindSuperFunction(method);
286                    }
287                    continue;
288                }
289    
290                // TODO: Add propagation for other kotlin descriptors (KT-3621)
291                if (superFun instanceof FunctionDescriptor) {
292                    superFunctions.add(substituteSuperFunction(superclassToSupertype, (FunctionDescriptor) superFun));
293                }
294            }
295    
296            // sorting for diagnostic stability
297            Collections.sort(superFunctions, new Comparator<FunctionDescriptor>() {
298                @Override
299                public int compare(FunctionDescriptor fun1, FunctionDescriptor fun2) {
300                    FqNameUnsafe fqName1 = getFqName(fun1.getContainingDeclaration());
301                    FqNameUnsafe fqName2 = getFqName(fun2.getContainingDeclaration());
302                    return fqName1.asString().compareTo(fqName2.asString());
303                }
304            });
305            return superFunctions;
306        }
307    
308        @NotNull
309        private static Multimap<FqName, Pair<FunctionDescriptor, JavaMethodImpl>> getSuperclassToFunctionsMultimap(
310                @NotNull JavaMethod method,
311                @NotNull BindingContext bindingContext,
312                @NotNull ClassDescriptor containingClass
313        ) {
314            Multimap<FqName, Pair<FunctionDescriptor, JavaMethodImpl>> result = HashMultimap.create();
315    
316            Name functionName = method.getName();
317            int parameterCount = method.getValueParameters().size();
318    
319            for (JetType supertype : TypeUtils.getAllSupertypes(containingClass.getDefaultType())) {
320                ClassifierDescriptor klass = supertype.getConstructor().getDeclarationDescriptor();
321                assert klass != null;
322                FqName fqName = DescriptorUtils.getFqNameSafe(klass);
323    
324                for (FunctionDescriptor fun : klass.getDefaultType().getMemberScope().getFunctions(functionName)) {
325                    CallableMemberDescriptor.Kind kind = fun.getKind();
326                    if ((kind == CallableMemberDescriptor.Kind.DECLARATION || kind == CallableMemberDescriptor.Kind.DELEGATION) &&
327                        fun.getValueParameters().size() + (fun.getReceiverParameter() != null ? 1 : 0) == parameterCount) {
328                        PsiElement declaration = BindingContextUtils.descriptorToDeclaration(bindingContext, fun);
329                        if (declaration instanceof PsiMethod) {
330                            result.put(fqName, Pair.create(fun, new JavaMethodImpl((PsiMethod) declaration)));
331                        } // else declaration is null or JetNamedFunction: both cases are processed later
332                    }
333                }
334            }
335            return result;
336        }
337    
338        @Nullable
339        private static DeclarationDescriptor findSuperFunction(
340                @NotNull Collection<Pair<FunctionDescriptor, JavaMethodImpl>> superFunctionCandidates,
341                @NotNull JavaMethodImpl superMethod
342        ) {
343            PsiManager psiManager = PsiManager.getInstance(superMethod.getPsi().getProject());
344            for (Pair<FunctionDescriptor, JavaMethodImpl> candidate : superFunctionCandidates) {
345                if (psiManager.areElementsEquivalent(candidate.second.getPsi(), superMethod.getPsi())) {
346                    return candidate.first;
347                }
348            }
349            return null;
350        }
351    
352        private boolean checkIfShouldBeExtension() {
353            boolean someSupersExtension = false;
354            boolean someSupersNotExtension = false;
355    
356            for (FunctionDescriptor superFunction : superFunctions) {
357                if (superFunction.getReceiverParameter() != null)  {
358                    someSupersExtension = true;
359                }
360                else {
361                    someSupersNotExtension = true;
362                }
363            }
364    
365            if (someSupersExtension) {
366                if (someSupersNotExtension) {
367                    reportError("Incompatible super methods: some are extension functions, some are not");
368                }
369                else {
370                    return true;
371                }
372            }
373            return false;
374        }
375    
376        @NotNull
377        private VarargCheckResult checkVarargInSuperFunctions(@NotNull ValueParameterDescriptor originalParam) {
378            boolean someSupersVararg = false;
379            boolean someSupersNotVararg = false;
380            for (FunctionDescriptor superFunction : superFunctions) {
381                int originalIndex = originalParam.getIndex();
382                int index = superFunction.getReceiverParameter() != null ? originalIndex - 1 : originalIndex;
383                if (index != -1 && superFunction.getValueParameters().get(index).getVarargElementType() != null) {
384                    someSupersVararg = true;
385                }
386                else {
387                    someSupersNotVararg = true;
388                }
389            }
390    
391            JetType originalVarargElementType = originalParam.getVarargElementType();
392            JetType originalType = originalParam.getType();
393    
394            if (someSupersVararg && someSupersNotVararg) {
395                reportError("Incompatible super methods: some have vararg parameter, some have not");
396                return new VarargCheckResult(originalType, originalVarargElementType != null);
397            }
398    
399            KotlinBuiltIns builtIns = KotlinBuiltIns.getInstance();
400            if (someSupersVararg && originalVarargElementType == null) {
401                // convert to vararg
402    
403                assert isArrayType(originalType);
404    
405                if (builtIns.isPrimitiveArray(originalType)) {
406                    // replace IntArray? with IntArray
407                    return new VarargCheckResult(TypeUtils.makeNotNullable(originalType), true);
408                }
409    
410                // replace Array<out Foo>? with Array<Foo>
411                JetType varargElementType = builtIns.getArrayElementType(originalType);
412                return new VarargCheckResult(builtIns.getArrayType(INVARIANT, varargElementType), true);
413            }
414            else if (someSupersNotVararg && originalVarargElementType != null) {
415                // convert to non-vararg
416    
417                assert isArrayType(originalType);
418    
419                if (builtIns.isPrimitiveArray(originalType)) {
420                    // replace IntArray with IntArray?
421                    return new VarargCheckResult(TypeUtils.makeNullable(originalType), false);
422                }
423    
424                // replace Array<Foo> with Array<out Foo>?
425                return new VarargCheckResult(TypeUtils.makeNullable(builtIns.getArrayType(Variance.OUT_VARIANCE, originalVarargElementType)),
426                                             false);
427            }
428    
429            return new VarargCheckResult(originalType, originalVarargElementType != null);
430        }
431    
432        @NotNull
433        private JetType modifyTypeAccordingToSuperMethods(
434                @NotNull JetType autoType,
435                @NotNull List<TypeAndVariance> typesFromSuper,
436                @NotNull TypeUsage howThisTypeIsUsed
437        ) {
438            if (autoType.isError()) {
439                return autoType;
440            }
441    
442            boolean resultNullable = typeMustBeNullable(autoType, typesFromSuper, howThisTypeIsUsed);
443            ClassifierDescriptor resultClassifier = modifyTypeClassifier(autoType, typesFromSuper);
444            List<TypeProjection> resultArguments = getTypeArgsOfType(autoType, resultClassifier, typesFromSuper);
445            JetScope resultScope;
446            if (resultClassifier instanceof ClassDescriptor) {
447                resultScope = ((ClassDescriptor) resultClassifier).getMemberScope(resultArguments);
448            }
449            else {
450                resultScope = autoType.getMemberScope();
451            }
452    
453            JetTypeImpl type = new JetTypeImpl(autoType.getAnnotations(),
454                                               resultClassifier.getTypeConstructor(),
455                                               resultNullable,
456                                               resultArguments,
457                                               resultScope);
458    
459            PropagationHeuristics.checkArrayInReturnType(this, type, typesFromSuper);
460            return type;
461        }
462    
463        @NotNull
464        private List<TypeProjection> getTypeArgsOfType(
465                @NotNull JetType autoType,
466                @NotNull ClassifierDescriptor classifier,
467                @NotNull List<TypeAndVariance> typesFromSuper
468        ) {
469            List<TypeProjection> autoArguments = autoType.getArguments();
470    
471            if (!(classifier instanceof ClassDescriptor)) {
472                assert autoArguments.isEmpty() :
473                        "Unexpected type arguments when type constructor is not ClassDescriptor, type = " + autoType;
474                return autoArguments;
475            }
476    
477            List<List<TypeProjectionAndVariance>> typeArgumentsFromSuper = calculateTypeArgumentsFromSuper((ClassDescriptor) classifier,
478                                                                                                           typesFromSuper);
479    
480            // Modify type arguments using info from typesFromSuper
481            List<TypeProjection> resultArguments = Lists.newArrayList();
482            for (TypeParameterDescriptor parameter : classifier.getTypeConstructor().getParameters()) {
483                TypeProjection argument = autoArguments.get(parameter.getIndex());
484    
485                JetType argumentType = argument.getType();
486                List<TypeProjectionAndVariance> projectionsFromSuper = typeArgumentsFromSuper.get(parameter.getIndex());
487                List<TypeAndVariance> argTypesFromSuper = getTypes(projectionsFromSuper);
488    
489                JetType type = modifyTypeAccordingToSuperMethods(argumentType, argTypesFromSuper, TYPE_ARGUMENT);
490                Variance projectionKind = calculateArgumentProjectionKindFromSuper(argument, projectionsFromSuper);
491    
492                resultArguments.add(new TypeProjectionImpl(projectionKind, type));
493            }
494            return resultArguments;
495        }
496    
497        private Variance calculateArgumentProjectionKindFromSuper(
498                @NotNull TypeProjection argument,
499                @NotNull List<TypeProjectionAndVariance> projectionsFromSuper
500        ) {
501            Set<Variance> projectionKindsInSuper = Sets.newLinkedHashSet();
502            for (TypeProjectionAndVariance projectionAndVariance : projectionsFromSuper) {
503                projectionKindsInSuper.add(projectionAndVariance.typeProjection.getProjectionKind());
504            }
505    
506            Variance defaultProjectionKind = argument.getProjectionKind();
507            if (projectionKindsInSuper.size() == 0) {
508                return defaultProjectionKind;
509            }
510            else if (projectionKindsInSuper.size() == 1) {
511                Variance projectionKindInSuper = projectionKindsInSuper.iterator().next();
512                if (defaultProjectionKind == INVARIANT || defaultProjectionKind == projectionKindInSuper) {
513                    return projectionKindInSuper;
514                }
515                else {
516                    reportError("Incompatible projection kinds in type arguments of super methods' return types: "
517                                + projectionsFromSuper + ", defined in current: " + argument);
518                    return defaultProjectionKind;
519                }
520            }
521            else {
522                reportError("Incompatible projection kinds in type arguments of super methods' return types: " + projectionsFromSuper);
523                return defaultProjectionKind;
524            }
525        }
526    
527        @NotNull
528        private static List<TypeAndVariance> getTypes(@NotNull List<TypeProjectionAndVariance> projections) {
529            List<TypeAndVariance> types = Lists.newArrayList();
530            for (TypeProjectionAndVariance projection : projections) {
531                types.add(new TypeAndVariance(projection.typeProjection.getType(),
532                                              merge(projection.varianceOfPosition, projection.typeProjection.getProjectionKind())));
533            }
534            return types;
535        }
536    
537        private static Variance merge(Variance positionOfOuter, Variance projectionKind) {
538            // Inv<Inv<out X>>, X is in invariant position
539            if (positionOfOuter == INVARIANT) return INVARIANT;
540            // Out<X>, X is in out-position
541            if (projectionKind == INVARIANT) return positionOfOuter;
542            // Out<Out<X>>, X is in out-position
543            // In<In<X>>, X is in out-position
544            // Out<In<X>>, X is in in-position
545            // In<Out<X>>, X is in in-position
546            return positionOfOuter.superpose(projectionKind);
547        }
548    
549        // Returns list with type arguments info from supertypes
550        // Example:
551        //     - Foo<A, B> is a subtype of Bar<A, List<B>>, Baz<Boolean, A>
552        //     - input: klass = Foo, typesFromSuper = [Bar<String, List<Int>>, Baz<Boolean, CharSequence>]
553        //     - output[0] = [String, CharSequence], output[1] = []
554        private static List<List<TypeProjectionAndVariance>> calculateTypeArgumentsFromSuper(
555                @NotNull ClassDescriptor klass,
556                @NotNull Collection<TypeAndVariance> typesFromSuper
557        ) {
558            // For each superclass of klass and its parameters, hold their mapping to klass' parameters
559            // #0 of Bar ->  A
560            // #1 of Bar ->  List<B>
561            // #0 of Baz ->  Boolean
562            // #1 of Baz ->  A
563            // #0 of Foo ->  A (mapped to itself)
564            // #1 of Foo ->  B (mapped to itself)
565            Multimap<TypeConstructor, TypeProjection> substitution = SubstitutionUtils.buildDeepSubstitutionMultimap(
566                    TypeUtils.makeUnsubstitutedType(klass, ErrorUtils.createErrorScope("Do not access this scope", true)));
567    
568            // for each parameter of klass, hold arguments in corresponding supertypes
569            List<List<TypeProjectionAndVariance>> parameterToArgumentsFromSuper = Lists.newArrayList();
570            for (TypeParameterDescriptor ignored : klass.getTypeConstructor().getParameters()) {
571                parameterToArgumentsFromSuper.add(new ArrayList<TypeProjectionAndVariance>());
572            }
573    
574            // Enumerate all types from super and all its parameters
575            for (TypeAndVariance typeFromSuper : typesFromSuper) {
576                for (TypeParameterDescriptor parameter : typeFromSuper.type.getConstructor().getParameters()) {
577                    TypeProjection argument = typeFromSuper.type.getArguments().get(parameter.getIndex());
578    
579                    // for given example, this block is executed four times:
580                    // 1. typeFromSuper = Bar<String, List<Int>>,      parameter = "#0 of Bar",  argument = String
581                    // 2. typeFromSuper = Bar<String, List<Int>>,      parameter = "#1 of Bar",  argument = List<Int>
582                    // 3. typeFromSuper = Baz<Boolean, CharSequence>,  parameter = "#0 of Baz",  argument = Boolean
583                    // 4. typeFromSuper = Baz<Boolean, CharSequence>,  parameter = "#1 of Baz",  argument = CharSequence
584    
585                    // if it is mapped to klass' parameter, then store it into map
586                    for (TypeProjection projection : substitution.get(parameter.getTypeConstructor())) {
587                        // 1. projection = A
588                        // 2. projection = List<B>
589                        // 3. projection = Boolean
590                        // 4. projection = A
591                        ClassifierDescriptor classifier = projection.getType().getConstructor().getDeclarationDescriptor();
592    
593                        // this condition is true for 1 and 4, false for 2 and 3
594                        if (classifier instanceof TypeParameterDescriptor && classifier.getContainingDeclaration() == klass) {
595                            int parameterIndex = ((TypeParameterDescriptor) classifier).getIndex();
596                            Variance effectiveVariance = parameter.getVariance().superpose(typeFromSuper.varianceOfPosition);
597                            parameterToArgumentsFromSuper.get(parameterIndex).add(new TypeProjectionAndVariance(argument, effectiveVariance));
598                        }
599                    }
600                }
601            }
602            return parameterToArgumentsFromSuper;
603        }
604    
605        private boolean typeMustBeNullable(
606                @NotNull JetType autoType,
607                @NotNull List<TypeAndVariance> typesFromSuper,
608                @NotNull TypeUsage howThisTypeIsUsed
609        ) {
610            boolean someSupersNotCovariantNullable = false;
611            boolean someSupersCovariantNullable = false;
612            boolean someSupersNotNull = false;
613            for (TypeAndVariance typeFromSuper : typesFromSuper) {
614                if (!typeFromSuper.type.isNullable()) {
615                    someSupersNotNull = true;
616                }
617                else {
618                    if (typeFromSuper.varianceOfPosition == Variance.OUT_VARIANCE) {
619                        someSupersCovariantNullable = true;
620                    }
621                    else {
622                        someSupersNotCovariantNullable = true;
623                    }
624                }
625            }
626    
627            if (someSupersNotNull && someSupersNotCovariantNullable) {
628                reportError("Incompatible types in superclasses: " + typesFromSuper);
629                return autoType.isNullable();
630            }
631            else if (someSupersNotNull) {
632                return false;
633            }
634            else if (someSupersNotCovariantNullable || someSupersCovariantNullable) {
635                boolean annotatedAsNotNull = howThisTypeIsUsed != TYPE_ARGUMENT && !autoType.isNullable();
636    
637                if (annotatedAsNotNull && someSupersNotCovariantNullable) {
638                    DescriptorRenderer renderer = DescriptorRenderer.SOURCE_CODE_SHORT_NAMES_IN_TYPES;
639                    reportError("In superclass type is nullable: " + typesFromSuper + ", in subclass it is not: " + renderer.renderType(autoType));
640                    return true;
641                }
642    
643                return !annotatedAsNotNull;
644            }
645            return autoType.isNullable();
646        }
647    
648        @NotNull
649        private ClassifierDescriptor modifyTypeClassifier(
650                @NotNull JetType autoType,
651                @NotNull List<TypeAndVariance> typesFromSuper
652        ) {
653            ClassifierDescriptor classifier = autoType.getConstructor().getDeclarationDescriptor();
654            if (!(classifier instanceof ClassDescriptor)) {
655                assert classifier != null : "no declaration descriptor for type " + autoType;
656    
657                if (classifier instanceof TypeParameterDescriptor && autoTypeParameterToModified.containsKey(classifier)) {
658                    return autoTypeParameterToModified.get(classifier);
659                }
660                return classifier;
661            }
662            ClassDescriptor klass = (ClassDescriptor) classifier;
663    
664            CollectionClassMapping collectionMapping = CollectionClassMapping.getInstance();
665    
666            boolean someSupersMutable = false;
667            boolean someSupersCovariantReadOnly = false;
668            boolean someSupersNotCovariantReadOnly = false;
669            for (TypeAndVariance typeFromSuper : typesFromSuper) {
670                ClassifierDescriptor classifierFromSuper = typeFromSuper.type.getConstructor().getDeclarationDescriptor();
671                if (classifierFromSuper instanceof ClassDescriptor) {
672                    ClassDescriptor classFromSuper = (ClassDescriptor) classifierFromSuper;
673    
674                    if (collectionMapping.isMutableCollection(classFromSuper)) {
675                        someSupersMutable = true;
676                    }
677                    else if (collectionMapping.isReadOnlyCollection(classFromSuper)) {
678                        if (typeFromSuper.varianceOfPosition == Variance.OUT_VARIANCE) {
679                            someSupersCovariantReadOnly = true;
680                        }
681                        else {
682                            someSupersNotCovariantReadOnly = true;
683                        }
684                    }
685                }
686            }
687    
688            if (someSupersMutable && someSupersNotCovariantReadOnly) {
689                reportError("Incompatible types in superclasses: " + typesFromSuper);
690                return classifier;
691            }
692            else if (someSupersMutable) {
693                if (collectionMapping.isReadOnlyCollection(klass)) {
694                    return collectionMapping.convertReadOnlyToMutable(klass);
695                }
696            }
697            else if (someSupersNotCovariantReadOnly || someSupersCovariantReadOnly) {
698                if (collectionMapping.isMutableCollection(klass)) {
699                    return collectionMapping.convertMutableToReadOnly(klass);
700                }
701            }
702    
703            ClassifierDescriptor fixed = PropagationHeuristics.tryToFixOverridingTWithRawType(this, typesFromSuper);
704            return fixed != null ? fixed : classifier;
705        }
706    
707        private static Map<ClassDescriptor, JetType> getSuperclassToSupertypeMap(ClassDescriptor containingClass) {
708            Map<ClassDescriptor, JetType> superclassToSupertype = Maps.newHashMap();
709            for (JetType supertype : TypeUtils.getAllSupertypes(containingClass.getDefaultType())) {
710                ClassifierDescriptor superclass = supertype.getConstructor().getDeclarationDescriptor();
711                assert superclass instanceof ClassDescriptor;
712                superclassToSupertype.put((ClassDescriptor) superclass, supertype);
713            }
714            return superclassToSupertype;
715        }
716    
717        @NotNull
718        private static FunctionDescriptor substituteSuperFunction(
719                @NotNull Map<ClassDescriptor, JetType> superclassToSupertype,
720                @NotNull FunctionDescriptor superFun
721        ) {
722            DeclarationDescriptor superFunContainer = superFun.getContainingDeclaration();
723            assert superFunContainer instanceof ClassDescriptor: superFunContainer;
724    
725            JetType supertype = superclassToSupertype.get(superFunContainer);
726            assert supertype != null : "Couldn't find super type for super function: " + superFun;
727            TypeSubstitutor supertypeSubstitutor = TypeSubstitutor.create(supertype);
728    
729            FunctionDescriptor substitutedSuperFun = superFun.substitute(supertypeSubstitutor);
730            assert substitutedSuperFun != null;
731            return substitutedSuperFun;
732        }
733    
734        private static boolean isArrayType(@NotNull JetType type) {
735            KotlinBuiltIns builtIns = KotlinBuiltIns.getInstance();
736            return builtIns.isArray(type) || builtIns.isPrimitiveArray(type);
737        }
738    
739        private static void reportCantFindSuperFunction(@NotNull JavaMethod javaMethod) {
740            String errorMessage = "Can't find super function for " + javaMethod + " defined in " + javaMethod.getContainingClass();
741            if (SystemInfo.isMac) {
742                LOG.error("Remove duplicates from your JDK definition\n" + errorMessage);
743            }
744            else {
745                LOG.error(errorMessage);
746            }
747        }
748    
749        private static class VarargCheckResult {
750            public final JetType parameterType;
751            public final boolean isVararg;
752    
753            public VarargCheckResult(JetType parameterType, boolean isVararg) {
754                this.parameterType = parameterType;
755                this.isVararg = isVararg;
756            }
757        }
758    
759        private static class TypeProjectionAndVariance {
760            public final TypeProjection typeProjection;
761            public final Variance varianceOfPosition;
762    
763            public TypeProjectionAndVariance(TypeProjection typeProjection, Variance varianceOfPosition) {
764                this.typeProjection = typeProjection;
765                this.varianceOfPosition = varianceOfPosition;
766            }
767    
768            public String toString() {
769                return typeProjection.toString();
770            }
771        }
772    
773        static class TypeAndVariance {
774            public final JetType type;
775            public final Variance varianceOfPosition;
776    
777            public TypeAndVariance(JetType type, Variance varianceOfPosition) {
778                this.type = type;
779                this.varianceOfPosition = varianceOfPosition;
780            }
781    
782            public String toString() {
783                return type.toString();
784            }
785        }
786    
787        private static class TypeAndName {
788            public final JetType type;
789            public final Name name;
790    
791            public TypeAndName(JetType type, Name name) {
792                this.type = type;
793                this.name = name;
794            }
795        }
796    
797        private static class ValueParameters {
798            private final JetType receiverType;
799            private final List<ValueParameterDescriptor> descriptors;
800            private final boolean hasStableParameterNames;
801    
802            public ValueParameters(
803                    @Nullable JetType receiverType,
804                    @NotNull List<ValueParameterDescriptor> descriptors,
805                    boolean hasStableParameterNames
806            ) {
807                this.receiverType = receiverType;
808                this.descriptors = descriptors;
809                this.hasStableParameterNames = hasStableParameterNames;
810            }
811        }
812    }