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.Lists;
020    import com.google.common.collect.Multimap;
021    import com.google.common.collect.Sets;
022    import com.intellij.util.Function;
023    import com.intellij.util.containers.ContainerUtil;
024    import kotlin.Function1;
025    import kotlin.KotlinPackage;
026    import org.jetbrains.annotations.NotNull;
027    import org.jetbrains.annotations.Nullable;
028    import org.jetbrains.jet.lang.descriptors.*;
029    import org.jetbrains.jet.lang.descriptors.annotations.Annotations;
030    import org.jetbrains.jet.lang.descriptors.impl.TypeParameterDescriptorImpl;
031    import org.jetbrains.jet.lang.descriptors.impl.ValueParameterDescriptorImpl;
032    import org.jetbrains.jet.lang.resolve.DescriptorUtils;
033    import org.jetbrains.jet.lang.resolve.java.jvmSignature.KotlinToJvmSignatureMapper;
034    import org.jetbrains.jet.lang.resolve.java.descriptor.JavaMethodDescriptor;
035    import org.jetbrains.jet.lang.resolve.java.jvmSignature.JvmMethodSignature;
036    import org.jetbrains.jet.lang.resolve.java.jvmSignature.JvmSignaturePackage;
037    import org.jetbrains.jet.lang.resolve.java.resolver.DescriptorResolverUtils;
038    import org.jetbrains.jet.lang.resolve.java.resolver.TypeUsage;
039    import org.jetbrains.jet.lang.resolve.java.structure.JavaMethod;
040    import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe;
041    import org.jetbrains.jet.lang.resolve.name.Name;
042    import org.jetbrains.jet.lang.resolve.scopes.JetScope;
043    import org.jetbrains.jet.lang.types.*;
044    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
045    import org.jetbrains.jet.renderer.DescriptorRenderer;
046    
047    import java.util.*;
048    
049    import static org.jetbrains.jet.lang.resolve.DescriptorUtils.getFqName;
050    import static org.jetbrains.jet.lang.resolve.java.resolver.TypeUsage.*;
051    import static org.jetbrains.jet.lang.types.Variance.INVARIANT;
052    
053    public class SignaturesPropagationData {
054    
055        private static final KotlinToJvmSignatureMapper SIGNATURE_MAPPER = ServiceLoader.load(
056                KotlinToJvmSignatureMapper.class,
057                KotlinToJvmSignatureMapper.class.getClassLoader()
058        ).iterator().next();
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 JavaMethod method
076        ) {
077            this.containingClass = containingClass;
078    
079            JavaMethodDescriptor autoMethodDescriptor =
080                    createAutoMethodDescriptor(containingClass, method, autoReturnType, receiverType, autoValueParameters, autoTypeParameters);
081    
082            superFunctions = getSuperFunctionsForMethod(method, autoMethodDescriptor, 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        @NotNull
092        private static JavaMethodDescriptor createAutoMethodDescriptor(
093                @NotNull ClassDescriptor containingClass,
094                @NotNull JavaMethod method, JetType autoReturnType,
095                @Nullable JetType receiverType,
096                @NotNull List<ValueParameterDescriptor> autoValueParameters,
097                @NotNull List<TypeParameterDescriptor> autoTypeParameters
098        ) {
099            JavaMethodDescriptor autoMethodDescriptor = JavaMethodDescriptor.createJavaMethod(
100                    containingClass,
101                    Annotations.EMPTY,
102                    method.getName()
103            );
104            autoMethodDescriptor.initialize(
105                    receiverType,
106                    containingClass.getThisAsReceiverParameter(),
107                    autoTypeParameters,
108                    autoValueParameters,
109                    autoReturnType,
110                    Modality.OPEN,
111                    Visibilities.PUBLIC
112            );
113            return autoMethodDescriptor;
114        }
115    
116        public List<TypeParameterDescriptor> getModifiedTypeParameters() {
117            return modifiedTypeParameters;
118        }
119    
120        public JetType getModifiedReceiverType() {
121            return modifiedValueParameters.receiverType;
122        }
123    
124        public List<ValueParameterDescriptor> getModifiedValueParameters() {
125            return modifiedValueParameters.descriptors;
126        }
127    
128        public boolean getModifiedHasStableParameterNames() {
129            return modifiedValueParameters.hasStableParameterNames;
130        }
131    
132        public JetType getModifiedReturnType() {
133            return modifiedReturnType;
134        }
135    
136        public List<String> getSignatureErrors() {
137            return signatureErrors;
138        }
139    
140        public List<FunctionDescriptor> getSuperFunctions() {
141            return superFunctions;
142        }
143    
144        void reportError(String error) {
145            signatureErrors.add(error);
146        }
147    
148        private JetType modifyReturnTypeAccordingToSuperMethods(
149                @NotNull JetType autoType // type built by JavaTypeTransformer
150        ) {
151            List<TypeAndVariance> typesFromSuperMethods = ContainerUtil.map(superFunctions,
152                    new Function<FunctionDescriptor, TypeAndVariance>() {
153                        @Override
154                        public TypeAndVariance fun(FunctionDescriptor superFunction) {
155                            return new TypeAndVariance(superFunction.getReturnType(), Variance.OUT_VARIANCE);
156                        }
157                    });
158    
159            return modifyTypeAccordingToSuperMethods(autoType, typesFromSuperMethods, MEMBER_SIGNATURE_COVARIANT);
160        }
161    
162        private List<TypeParameterDescriptor> modifyTypeParametersAccordingToSuperMethods(List<TypeParameterDescriptor> autoTypeParameters) {
163            List<TypeParameterDescriptor> result = Lists.newArrayList();
164    
165            for (TypeParameterDescriptor autoParameter : autoTypeParameters) {
166                int index = autoParameter.getIndex();
167                TypeParameterDescriptorImpl modifiedTypeParameter = autoTypeParameterToModified.get(autoParameter);
168    
169                List<Iterator<JetType>> upperBoundFromSuperFunctionsIterators = Lists.newArrayList();
170                for (FunctionDescriptor superFunction : superFunctions) {
171                    upperBoundFromSuperFunctionsIterators.add(superFunction.getTypeParameters().get(index).getUpperBounds().iterator());
172                }
173    
174                for (JetType autoUpperBound : autoParameter.getUpperBounds()) {
175                    List<TypeAndVariance> upperBoundsFromSuperFunctions = Lists.newArrayList();
176    
177                    for (Iterator<JetType> iterator : upperBoundFromSuperFunctionsIterators) {
178                        assert iterator.hasNext();
179                        upperBoundsFromSuperFunctions.add(new TypeAndVariance(iterator.next(), INVARIANT));
180                    }
181    
182                    JetType modifiedUpperBound = modifyTypeAccordingToSuperMethods(autoUpperBound, upperBoundsFromSuperFunctions, UPPER_BOUND);
183                    modifiedTypeParameter.addUpperBound(modifiedUpperBound);
184                }
185    
186                for (Iterator<JetType> iterator : upperBoundFromSuperFunctionsIterators) {
187                    assert !iterator.hasNext();
188                }
189    
190                modifiedTypeParameter.setInitialized();
191                result.add(modifiedTypeParameter);
192            }
193    
194            return result;
195        }
196    
197        private ValueParameters modifyValueParametersAccordingToSuperMethods(
198                @Nullable JetType receiverType,
199                @NotNull List<ValueParameterDescriptor> parameters // descriptors built by parameters resolver
200        ) {
201            assert receiverType == null : "Parameters before propagation have receiver type," +
202                                          " but propagation should be disabled for functions compiled from Kotlin in class: " +
203                                          DescriptorUtils.getFqName(containingClass);
204    
205            JetType resultReceiverType = null;
206            List<ValueParameterDescriptor> resultParameters = Lists.newArrayList();
207    
208            boolean shouldBeExtension = checkIfShouldBeExtension();
209    
210            for (final ValueParameterDescriptor originalParam : parameters) {
211                final int originalIndex = originalParam.getIndex();
212                List<TypeAndName> typesFromSuperMethods = ContainerUtil.map(superFunctions,
213                        new Function<FunctionDescriptor, TypeAndName>() {
214                            @Override
215                            public TypeAndName fun(FunctionDescriptor superFunction) {
216                                ReceiverParameterDescriptor receiver = superFunction.getReceiverParameter();
217                                int index = receiver != null ? originalIndex - 1 : originalIndex;
218                                if (index == -1) {
219                                    assert receiver != null : "can't happen: index is -1, while function is not extension";
220                                    return new TypeAndName(receiver.getType(), originalParam.getName());
221                                }
222                                ValueParameterDescriptor parameter = superFunction.getValueParameters().get(index);
223                                return new TypeAndName(parameter.getType(), parameter.getName());
224                            }
225                        });
226    
227                VarargCheckResult varargCheckResult = checkVarargInSuperFunctions(originalParam);
228    
229                JetType altType = modifyTypeAccordingToSuperMethods(varargCheckResult.parameterType,
230                                                                    convertToTypeVarianceList(typesFromSuperMethods),
231                                                                    MEMBER_SIGNATURE_CONTRAVARIANT);
232    
233                if (shouldBeExtension && originalIndex == 0) {
234                    resultReceiverType = altType;
235                }
236                else {
237                    Name stableName = null;
238                    for (int i = 0; i < superFunctions.size(); i++) {
239                        if (superFunctions.get(i).hasStableParameterNames()) {
240                            // When there's more than one stable name in super functions, we pick the first one. This behaviour is similar to
241                            // the compiler front-end, except that it reports a warning in such cases
242                            // TODO: report a warning somewhere if there's more than one stable name in super functions
243                            stableName = typesFromSuperMethods.get(i).name;
244                            break;
245                        }
246                    }
247    
248                    resultParameters.add(new ValueParameterDescriptorImpl(
249                            originalParam.getContainingDeclaration(),
250                            null,
251                            shouldBeExtension ? originalIndex - 1 : originalIndex,
252                            originalParam.getAnnotations(),
253                            stableName != null ? stableName : originalParam.getName(),
254                            altType,
255                            originalParam.declaresDefaultValue(),
256                            varargCheckResult.isVararg ? KotlinBuiltIns.getInstance().getArrayElementType(altType) : null
257                    ));
258                }
259            }
260    
261            boolean hasStableParameterNames = KotlinPackage.any(superFunctions, new Function1<FunctionDescriptor, Boolean>() {
262                @Override
263                public Boolean invoke(FunctionDescriptor descriptor) {
264                    return descriptor.hasStableParameterNames();
265                }
266            });
267    
268            return new ValueParameters(resultReceiverType, resultParameters, hasStableParameterNames);
269        }
270    
271        @NotNull
272        private static List<TypeAndVariance> convertToTypeVarianceList(@NotNull List<TypeAndName> list) {
273            return KotlinPackage.map(list, new Function1<TypeAndName, TypeAndVariance>() {
274                @Override
275                public TypeAndVariance invoke(TypeAndName tvn) {
276                    return new TypeAndVariance(tvn.type, INVARIANT);
277                }
278            });
279        }
280    
281        private static List<FunctionDescriptor> getSuperFunctionsForMethod(
282                @NotNull JavaMethod method,
283                @NotNull JavaMethodDescriptor autoMethodDescriptor,
284                @NotNull ClassDescriptor containingClass
285        ) {
286            List<FunctionDescriptor> superFunctions = Lists.newArrayList();
287    
288            // TODO: Add propagation for other kotlin descriptors (KT-3621)
289            Name name = method.getName();
290            JvmMethodSignature autoSignature = SIGNATURE_MAPPER.mapToJvmMethodSignature(autoMethodDescriptor);
291            for (JetType supertype : containingClass.getTypeConstructor().getSupertypes()) {
292                Collection<FunctionDescriptor> superFunctionCandidates = supertype.getMemberScope().getFunctions(name);
293                for (FunctionDescriptor candidate : superFunctionCandidates) {
294                    JvmMethodSignature candidateSignature = SIGNATURE_MAPPER.mapToJvmMethodSignature(candidate);
295                    if (JvmSignaturePackage.erasedSignaturesEqualIgnoringReturnTypes(autoSignature, candidateSignature)) {
296                        superFunctions.add(candidate);
297                    }
298                }
299            }
300    
301            // sorting for diagnostic stability
302            Collections.sort(superFunctions, new Comparator<FunctionDescriptor>() {
303                @Override
304                public int compare(@NotNull FunctionDescriptor fun1, @NotNull FunctionDescriptor fun2) {
305                    FqNameUnsafe fqName1 = getFqName(fun1.getContainingDeclaration());
306                    FqNameUnsafe fqName2 = getFqName(fun2.getContainingDeclaration());
307                    return fqName1.asString().compareTo(fqName2.asString());
308                }
309            });
310            return superFunctions;
311        }
312    
313        private boolean checkIfShouldBeExtension() {
314            boolean someSupersExtension = false;
315            boolean someSupersNotExtension = false;
316    
317            for (FunctionDescriptor superFunction : superFunctions) {
318                if (superFunction.getReceiverParameter() != null)  {
319                    someSupersExtension = true;
320                }
321                else {
322                    someSupersNotExtension = true;
323                }
324            }
325    
326            if (someSupersExtension) {
327                if (someSupersNotExtension) {
328                    reportError("Incompatible super methods: some are extension functions, some are not");
329                }
330                else {
331                    return true;
332                }
333            }
334            return false;
335        }
336    
337        @NotNull
338        private VarargCheckResult checkVarargInSuperFunctions(@NotNull ValueParameterDescriptor originalParam) {
339            boolean someSupersVararg = false;
340            boolean someSupersNotVararg = false;
341            for (FunctionDescriptor superFunction : superFunctions) {
342                int originalIndex = originalParam.getIndex();
343                int index = superFunction.getReceiverParameter() != null ? originalIndex - 1 : originalIndex;
344                if (index != -1 && superFunction.getValueParameters().get(index).getVarargElementType() != null) {
345                    someSupersVararg = true;
346                }
347                else {
348                    someSupersNotVararg = true;
349                }
350            }
351    
352            JetType originalVarargElementType = originalParam.getVarargElementType();
353            JetType originalType = originalParam.getType();
354    
355            if (someSupersVararg && someSupersNotVararg) {
356                reportError("Incompatible super methods: some have vararg parameter, some have not");
357                return new VarargCheckResult(originalType, originalVarargElementType != null);
358            }
359    
360            KotlinBuiltIns builtIns = KotlinBuiltIns.getInstance();
361            if (someSupersVararg && originalVarargElementType == null) {
362                // convert to vararg
363    
364                assert isArrayType(originalType);
365    
366                if (builtIns.isPrimitiveArray(originalType)) {
367                    // replace IntArray? with IntArray
368                    return new VarargCheckResult(TypeUtils.makeNotNullable(originalType), true);
369                }
370    
371                // replace Array<out Foo>? with Array<Foo>
372                JetType varargElementType = builtIns.getArrayElementType(originalType);
373                return new VarargCheckResult(builtIns.getArrayType(INVARIANT, varargElementType), true);
374            }
375            else if (someSupersNotVararg && originalVarargElementType != null) {
376                // convert to non-vararg
377    
378                assert isArrayType(originalType);
379    
380                if (builtIns.isPrimitiveArray(originalType)) {
381                    // replace IntArray with IntArray?
382                    return new VarargCheckResult(TypeUtils.makeNullable(originalType), false);
383                }
384    
385                // replace Array<Foo> with Array<out Foo>?
386                return new VarargCheckResult(TypeUtils.makeNullable(builtIns.getArrayType(Variance.OUT_VARIANCE, originalVarargElementType)),
387                                             false);
388            }
389    
390            return new VarargCheckResult(originalType, originalVarargElementType != null);
391        }
392    
393        @NotNull
394        private JetType modifyTypeAccordingToSuperMethods(
395                @NotNull JetType autoType,
396                @NotNull List<TypeAndVariance> typesFromSuper,
397                @NotNull TypeUsage howThisTypeIsUsed
398        ) {
399            if (autoType.isError()) {
400                return autoType;
401            }
402    
403            boolean resultNullable = typeMustBeNullable(autoType, typesFromSuper, howThisTypeIsUsed);
404            ClassifierDescriptor resultClassifier = modifyTypeClassifier(autoType, typesFromSuper);
405            List<TypeProjection> resultArguments = getTypeArgsOfType(autoType, resultClassifier, typesFromSuper);
406            JetScope resultScope;
407            if (resultClassifier instanceof ClassDescriptor) {
408                resultScope = ((ClassDescriptor) resultClassifier).getMemberScope(resultArguments);
409            }
410            else {
411                resultScope = autoType.getMemberScope();
412            }
413    
414            JetTypeImpl type = new JetTypeImpl(autoType.getAnnotations(),
415                                               resultClassifier.getTypeConstructor(),
416                                               resultNullable,
417                                               resultArguments,
418                                               resultScope);
419    
420            PropagationHeuristics.checkArrayInReturnType(this, type, typesFromSuper);
421            return type;
422        }
423    
424        @NotNull
425        private List<TypeProjection> getTypeArgsOfType(
426                @NotNull JetType autoType,
427                @NotNull ClassifierDescriptor classifier,
428                @NotNull List<TypeAndVariance> typesFromSuper
429        ) {
430            List<TypeProjection> autoArguments = autoType.getArguments();
431    
432            if (!(classifier instanceof ClassDescriptor)) {
433                assert autoArguments.isEmpty() :
434                        "Unexpected type arguments when type constructor is not ClassDescriptor, type = " + autoType;
435                return autoArguments;
436            }
437    
438            List<List<TypeProjectionAndVariance>> typeArgumentsFromSuper = calculateTypeArgumentsFromSuper((ClassDescriptor) classifier,
439                                                                                                           typesFromSuper);
440    
441            // Modify type arguments using info from typesFromSuper
442            List<TypeProjection> resultArguments = Lists.newArrayList();
443            for (TypeParameterDescriptor parameter : classifier.getTypeConstructor().getParameters()) {
444                TypeProjection argument = autoArguments.get(parameter.getIndex());
445    
446                JetType argumentType = argument.getType();
447                List<TypeProjectionAndVariance> projectionsFromSuper = typeArgumentsFromSuper.get(parameter.getIndex());
448                List<TypeAndVariance> argTypesFromSuper = getTypes(projectionsFromSuper);
449    
450                JetType type = modifyTypeAccordingToSuperMethods(argumentType, argTypesFromSuper, TYPE_ARGUMENT);
451                Variance projectionKind = calculateArgumentProjectionKindFromSuper(argument, projectionsFromSuper);
452    
453                resultArguments.add(new TypeProjectionImpl(projectionKind, type));
454            }
455            return resultArguments;
456        }
457    
458        private Variance calculateArgumentProjectionKindFromSuper(
459                @NotNull TypeProjection argument,
460                @NotNull List<TypeProjectionAndVariance> projectionsFromSuper
461        ) {
462            Set<Variance> projectionKindsInSuper = Sets.newLinkedHashSet();
463            for (TypeProjectionAndVariance projectionAndVariance : projectionsFromSuper) {
464                projectionKindsInSuper.add(projectionAndVariance.typeProjection.getProjectionKind());
465            }
466    
467            Variance defaultProjectionKind = argument.getProjectionKind();
468            if (projectionKindsInSuper.size() == 0) {
469                return defaultProjectionKind;
470            }
471            else if (projectionKindsInSuper.size() == 1) {
472                Variance projectionKindInSuper = projectionKindsInSuper.iterator().next();
473                if (defaultProjectionKind == INVARIANT || defaultProjectionKind == projectionKindInSuper) {
474                    return projectionKindInSuper;
475                }
476                else {
477                    reportError("Incompatible projection kinds in type arguments of super methods' return types: "
478                                + projectionsFromSuper + ", defined in current: " + argument);
479                    return defaultProjectionKind;
480                }
481            }
482            else {
483                reportError("Incompatible projection kinds in type arguments of super methods' return types: " + projectionsFromSuper);
484                return defaultProjectionKind;
485            }
486        }
487    
488        @NotNull
489        private static List<TypeAndVariance> getTypes(@NotNull List<TypeProjectionAndVariance> projections) {
490            List<TypeAndVariance> types = Lists.newArrayList();
491            for (TypeProjectionAndVariance projection : projections) {
492                types.add(new TypeAndVariance(projection.typeProjection.getType(),
493                                              merge(projection.varianceOfPosition, projection.typeProjection.getProjectionKind())));
494            }
495            return types;
496        }
497    
498        private static Variance merge(Variance positionOfOuter, Variance projectionKind) {
499            // Inv<Inv<out X>>, X is in invariant position
500            if (positionOfOuter == INVARIANT) return INVARIANT;
501            // Out<X>, X is in out-position
502            if (projectionKind == INVARIANT) return positionOfOuter;
503            // Out<Out<X>>, X is in out-position
504            // In<In<X>>, X is in out-position
505            // Out<In<X>>, X is in in-position
506            // In<Out<X>>, X is in in-position
507            return positionOfOuter.superpose(projectionKind);
508        }
509    
510        // Returns list with type arguments info from supertypes
511        // Example:
512        //     - Foo<A, B> is a subtype of Bar<A, List<B>>, Baz<Boolean, A>
513        //     - input: klass = Foo, typesFromSuper = [Bar<String, List<Int>>, Baz<Boolean, CharSequence>]
514        //     - output[0] = [String, CharSequence], output[1] = []
515        private static List<List<TypeProjectionAndVariance>> calculateTypeArgumentsFromSuper(
516                @NotNull ClassDescriptor klass,
517                @NotNull Collection<TypeAndVariance> typesFromSuper
518        ) {
519            // For each superclass of klass and its parameters, hold their mapping to klass' parameters
520            // #0 of Bar ->  A
521            // #1 of Bar ->  List<B>
522            // #0 of Baz ->  Boolean
523            // #1 of Baz ->  A
524            // #0 of Foo ->  A (mapped to itself)
525            // #1 of Foo ->  B (mapped to itself)
526            Multimap<TypeConstructor, TypeProjection> substitution = SubstitutionUtils.buildDeepSubstitutionMultimap(
527                    TypeUtils.makeUnsubstitutedType(klass, ErrorUtils.createErrorScope("Do not access this scope", true)));
528    
529            // for each parameter of klass, hold arguments in corresponding supertypes
530            List<List<TypeProjectionAndVariance>> parameterToArgumentsFromSuper = Lists.newArrayList();
531            for (TypeParameterDescriptor ignored : klass.getTypeConstructor().getParameters()) {
532                parameterToArgumentsFromSuper.add(new ArrayList<TypeProjectionAndVariance>());
533            }
534    
535            // Enumerate all types from super and all its parameters
536            for (TypeAndVariance typeFromSuper : typesFromSuper) {
537                for (TypeParameterDescriptor parameter : typeFromSuper.type.getConstructor().getParameters()) {
538                    TypeProjection argument = typeFromSuper.type.getArguments().get(parameter.getIndex());
539    
540                    // for given example, this block is executed four times:
541                    // 1. typeFromSuper = Bar<String, List<Int>>,      parameter = "#0 of Bar",  argument = String
542                    // 2. typeFromSuper = Bar<String, List<Int>>,      parameter = "#1 of Bar",  argument = List<Int>
543                    // 3. typeFromSuper = Baz<Boolean, CharSequence>,  parameter = "#0 of Baz",  argument = Boolean
544                    // 4. typeFromSuper = Baz<Boolean, CharSequence>,  parameter = "#1 of Baz",  argument = CharSequence
545    
546                    // if it is mapped to klass' parameter, then store it into map
547                    for (TypeProjection projection : substitution.get(parameter.getTypeConstructor())) {
548                        // 1. projection = A
549                        // 2. projection = List<B>
550                        // 3. projection = Boolean
551                        // 4. projection = A
552                        ClassifierDescriptor classifier = projection.getType().getConstructor().getDeclarationDescriptor();
553    
554                        // this condition is true for 1 and 4, false for 2 and 3
555                        if (classifier instanceof TypeParameterDescriptor && classifier.getContainingDeclaration() == klass) {
556                            int parameterIndex = ((TypeParameterDescriptor) classifier).getIndex();
557                            Variance effectiveVariance = parameter.getVariance().superpose(typeFromSuper.varianceOfPosition);
558                            parameterToArgumentsFromSuper.get(parameterIndex).add(new TypeProjectionAndVariance(argument, effectiveVariance));
559                        }
560                    }
561                }
562            }
563            return parameterToArgumentsFromSuper;
564        }
565    
566        private boolean typeMustBeNullable(
567                @NotNull JetType autoType,
568                @NotNull List<TypeAndVariance> typesFromSuper,
569                @NotNull TypeUsage howThisTypeIsUsed
570        ) {
571            boolean someSupersNotCovariantNullable = false;
572            boolean someSupersCovariantNullable = false;
573            boolean someSupersNotNull = false;
574            for (TypeAndVariance typeFromSuper : typesFromSuper) {
575                if (!typeFromSuper.type.isNullable()) {
576                    someSupersNotNull = true;
577                }
578                else {
579                    if (typeFromSuper.varianceOfPosition == Variance.OUT_VARIANCE) {
580                        someSupersCovariantNullable = true;
581                    }
582                    else {
583                        someSupersNotCovariantNullable = true;
584                    }
585                }
586            }
587    
588            if (someSupersNotNull && someSupersNotCovariantNullable) {
589                reportError("Incompatible types in superclasses: " + typesFromSuper);
590                return autoType.isNullable();
591            }
592            else if (someSupersNotNull) {
593                return false;
594            }
595            else if (someSupersNotCovariantNullable || someSupersCovariantNullable) {
596                boolean annotatedAsNotNull = howThisTypeIsUsed != TYPE_ARGUMENT && !autoType.isNullable();
597    
598                if (annotatedAsNotNull && someSupersNotCovariantNullable) {
599                    DescriptorRenderer renderer = DescriptorRenderer.SOURCE_CODE_SHORT_NAMES_IN_TYPES;
600                    reportError("In superclass type is nullable: " + typesFromSuper + ", in subclass it is not: " + renderer.renderType(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 boolean isArrayType(@NotNull JetType type) {
669            KotlinBuiltIns builtIns = KotlinBuiltIns.getInstance();
670            return builtIns.isArray(type) || builtIns.isPrimitiveArray(type);
671        }
672    
673        private static class VarargCheckResult {
674            public final JetType parameterType;
675            public final boolean isVararg;
676    
677            public VarargCheckResult(JetType parameterType, boolean isVararg) {
678                this.parameterType = parameterType;
679                this.isVararg = isVararg;
680            }
681        }
682    
683        private static class TypeProjectionAndVariance {
684            public final TypeProjection typeProjection;
685            public final Variance varianceOfPosition;
686    
687            public TypeProjectionAndVariance(TypeProjection typeProjection, Variance varianceOfPosition) {
688                this.typeProjection = typeProjection;
689                this.varianceOfPosition = varianceOfPosition;
690            }
691    
692            public String toString() {
693                return typeProjection.toString();
694            }
695        }
696    
697        static class TypeAndVariance {
698            public final JetType type;
699            public final Variance varianceOfPosition;
700    
701            public TypeAndVariance(JetType type, Variance varianceOfPosition) {
702                this.type = type;
703                this.varianceOfPosition = varianceOfPosition;
704            }
705    
706            public String toString() {
707                return type.toString();
708            }
709        }
710    
711        private static class TypeAndName {
712            public final JetType type;
713            public final Name name;
714    
715            public TypeAndName(JetType type, Name name) {
716                this.type = type;
717                this.name = name;
718            }
719        }
720    
721        private static class ValueParameters {
722            private final JetType receiverType;
723            private final List<ValueParameterDescriptor> descriptors;
724            private final boolean hasStableParameterNames;
725    
726            public ValueParameters(
727                    @Nullable JetType receiverType,
728                    @NotNull List<ValueParameterDescriptor> descriptors,
729                    boolean hasStableParameterNames
730            ) {
731                this.receiverType = receiverType;
732                this.descriptors = descriptors;
733                this.hasStableParameterNames = hasStableParameterNames;
734            }
735        }
736    }