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