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