001    /*
002     * Copyright 2010-2015 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.kotlin.resolve.jvm.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.CollectionsKt;
025    import kotlin.jvm.functions.Function1;
026    import org.jetbrains.annotations.NotNull;
027    import org.jetbrains.annotations.Nullable;
028    import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
029    import org.jetbrains.kotlin.descriptors.*;
030    import org.jetbrains.kotlin.descriptors.annotations.Annotations;
031    import org.jetbrains.kotlin.descriptors.impl.TypeParameterDescriptorImpl;
032    import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl;
033    import org.jetbrains.kotlin.incremental.components.NoLookupLocation;
034    import org.jetbrains.kotlin.load.java.components.TypeUsage;
035    import org.jetbrains.kotlin.load.java.descriptors.JavaMethodDescriptor;
036    import org.jetbrains.kotlin.load.java.structure.JavaMethod;
037    import org.jetbrains.kotlin.name.FqNameUnsafe;
038    import org.jetbrains.kotlin.name.Name;
039    import org.jetbrains.kotlin.platform.JavaToKotlinClassMap;
040    import org.jetbrains.kotlin.renderer.DescriptorRenderer;
041    import org.jetbrains.kotlin.resolve.DescriptorUtils;
042    import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
043    import org.jetbrains.kotlin.resolve.jvm.JavaDescriptorResolverKt;
044    import org.jetbrains.kotlin.resolve.jvm.JavaResolverUtils;
045    import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature;
046    import org.jetbrains.kotlin.resolve.jvm.jvmSignature.KotlinToJvmSignatureMapper;
047    import org.jetbrains.kotlin.resolve.jvm.jvmSignature.KotlinToJvmSignatureMapperKt;
048    import org.jetbrains.kotlin.resolve.scopes.MemberScope;
049    import org.jetbrains.kotlin.types.*;
050    
051    import java.util.*;
052    
053    import static org.jetbrains.kotlin.load.java.components.TypeUsage.*;
054    import static org.jetbrains.kotlin.resolve.DescriptorUtils.getFqName;
055    import static org.jetbrains.kotlin.types.Variance.INVARIANT;
056    
057    public class SignaturesPropagationData {
058    
059        private static final KotlinToJvmSignatureMapper SIGNATURE_MAPPER = ServiceLoader.load(
060                KotlinToJvmSignatureMapper.class,
061                KotlinToJvmSignatureMapper.class.getClassLoader()
062        ).iterator().next();
063    
064        private final JavaMethodDescriptor autoMethodDescriptor;
065    
066        private final List<TypeParameterDescriptor> modifiedTypeParameters;
067        private final ValueParameters modifiedValueParameters;
068    
069        private final KotlinType modifiedReturnType;
070        private final List<String> signatureErrors = Lists.newArrayList();
071        private final List<FunctionDescriptor> superFunctions;
072        private final Map<TypeParameterDescriptor, TypeParameterDescriptorImpl> autoTypeParameterToModified;
073        final ClassDescriptor containingClass;
074    
075        public SignaturesPropagationData(
076                @NotNull ClassDescriptor containingClass,
077                @NotNull KotlinType autoReturnType, // type built by JavaTypeTransformer from Java signature and @NotNull annotations
078                @Nullable KotlinType receiverType,
079                @NotNull List<ValueParameterDescriptor> autoValueParameters, // descriptors built by parameters resolver
080                @NotNull List<TypeParameterDescriptor> autoTypeParameters, // descriptors built by signature resolver
081                @NotNull JavaMethod method
082        ) {
083            this.containingClass = containingClass;
084    
085            autoMethodDescriptor =
086                    createAutoMethodDescriptor(containingClass, method, autoReturnType, receiverType, autoValueParameters, autoTypeParameters);
087    
088            superFunctions = getSuperFunctionsForMethod(method, autoMethodDescriptor, containingClass);
089    
090            autoTypeParameterToModified = JavaResolverUtils.recreateTypeParametersAndReturnMapping(autoTypeParameters, null);
091    
092            modifiedTypeParameters = modifyTypeParametersAccordingToSuperMethods(autoTypeParameters);
093            modifiedReturnType = modifyReturnTypeAccordingToSuperMethods(autoReturnType);
094            modifiedValueParameters = modifyValueParametersAccordingToSuperMethods(receiverType, autoValueParameters);
095        }
096    
097        @NotNull
098        private static JavaMethodDescriptor createAutoMethodDescriptor(
099                @NotNull ClassDescriptor containingClass,
100                @NotNull JavaMethod method, KotlinType autoReturnType,
101                @Nullable KotlinType receiverType,
102                @NotNull List<ValueParameterDescriptor> autoValueParameters,
103                @NotNull List<TypeParameterDescriptor> autoTypeParameters
104        ) {
105            JavaMethodDescriptor autoMethodDescriptor = JavaMethodDescriptor.createJavaMethod(
106                    containingClass,
107                    Annotations.Companion.getEMPTY(),
108                    method.getName(),
109                    //TODO: what to do?
110                    SourceElement.NO_SOURCE
111            );
112            autoMethodDescriptor.initialize(
113                    receiverType,
114                    containingClass.getThisAsReceiverParameter(),
115                    autoTypeParameters,
116                    autoValueParameters,
117                    autoReturnType,
118                    Modality.OPEN,
119                    Visibilities.PUBLIC
120            );
121            return autoMethodDescriptor;
122        }
123    
124        public List<TypeParameterDescriptor> getModifiedTypeParameters() {
125            return modifiedTypeParameters;
126        }
127    
128        public KotlinType getModifiedReceiverType() {
129            return modifiedValueParameters.receiverType;
130        }
131    
132        public List<ValueParameterDescriptor> getModifiedValueParameters() {
133            return modifiedValueParameters.descriptors;
134        }
135    
136        public boolean getModifiedHasStableParameterNames() {
137            return modifiedValueParameters.hasStableParameterNames;
138        }
139    
140        public KotlinType getModifiedReturnType() {
141            return modifiedReturnType;
142        }
143    
144        public List<String> getSignatureErrors() {
145            return signatureErrors;
146        }
147    
148        public List<FunctionDescriptor> getSuperFunctions() {
149            return superFunctions;
150        }
151    
152        void reportError(String error) {
153            signatureErrors.add(error);
154        }
155    
156        private KotlinType modifyReturnTypeAccordingToSuperMethods(
157                @NotNull KotlinType autoType // type built by JavaTypeTransformer
158        ) {
159            if (JavaDescriptorResolverKt.getPLATFORM_TYPES()) return autoType;
160    
161            List<TypeAndVariance> typesFromSuperMethods = ContainerUtil.map(superFunctions,
162                                                                            new Function<FunctionDescriptor, TypeAndVariance>() {
163                                                                                @Override
164                                                                                public TypeAndVariance fun(FunctionDescriptor superFunction) {
165                                                                                    return new TypeAndVariance(superFunction.getReturnType(),
166                                                                                                               Variance.OUT_VARIANCE);
167                                                                                }
168                                                                            });
169    
170            return modifyTypeAccordingToSuperMethods(autoType, typesFromSuperMethods, MEMBER_SIGNATURE_COVARIANT);
171        }
172    
173        private List<TypeParameterDescriptor> modifyTypeParametersAccordingToSuperMethods(List<TypeParameterDescriptor> autoTypeParameters) {
174            if (JavaDescriptorResolverKt.getPLATFORM_TYPES()) return autoTypeParameters;
175    
176            List<TypeParameterDescriptor> result = Lists.newArrayList();
177    
178            for (TypeParameterDescriptor autoParameter : autoTypeParameters) {
179                int index = autoParameter.getIndex();
180                TypeParameterDescriptorImpl modifiedTypeParameter = autoTypeParameterToModified.get(autoParameter);
181    
182                List<Iterator<KotlinType>> upperBoundFromSuperFunctionsIterators = Lists.newArrayList();
183                for (FunctionDescriptor superFunction : superFunctions) {
184                    upperBoundFromSuperFunctionsIterators.add(superFunction.getTypeParameters().get(index).getUpperBounds().iterator());
185                }
186    
187                for (KotlinType autoUpperBound : autoParameter.getUpperBounds()) {
188                    List<TypeAndVariance> upperBoundsFromSuperFunctions = Lists.newArrayList();
189    
190                    for (Iterator<KotlinType> iterator : upperBoundFromSuperFunctionsIterators) {
191                        assert iterator.hasNext();
192                        upperBoundsFromSuperFunctions.add(new TypeAndVariance(iterator.next(), INVARIANT));
193                    }
194    
195                    KotlinType modifiedUpperBound = modifyTypeAccordingToSuperMethods(autoUpperBound, upperBoundsFromSuperFunctions, UPPER_BOUND);
196                    modifiedTypeParameter.addUpperBound(modifiedUpperBound);
197                }
198    
199                for (Iterator<KotlinType> iterator : upperBoundFromSuperFunctionsIterators) {
200                    assert !iterator.hasNext();
201                }
202    
203                modifiedTypeParameter.setInitialized();
204                result.add(modifiedTypeParameter);
205            }
206    
207            return result;
208        }
209    
210        private ValueParameters modifyValueParametersAccordingToSuperMethods(
211                @Nullable KotlinType receiverType,
212                @NotNull List<ValueParameterDescriptor> parameters // descriptors built by parameters resolver
213        ) {
214            assert receiverType == null : "Parameters before propagation have receiver type," +
215                                          " but propagation should be disabled for functions compiled from Kotlin in class: " +
216                                          DescriptorUtils.getFqName(containingClass);
217    
218            KotlinType resultReceiverType = null;
219            List<ValueParameterDescriptor> resultParameters = new ArrayList<ValueParameterDescriptor>(parameters.size());
220    
221            boolean shouldBeExtension = checkIfShouldBeExtension();
222    
223            for (final ValueParameterDescriptor originalParam : parameters) {
224                final int originalIndex = originalParam.getIndex();
225                List<TypeAndName> typesFromSuperMethods = ContainerUtil.map(superFunctions,
226                        new Function<FunctionDescriptor, TypeAndName>() {
227                            @Override
228                            public TypeAndName fun(FunctionDescriptor superFunction) {
229                                ReceiverParameterDescriptor receiver = superFunction.getExtensionReceiverParameter();
230                                int index = receiver != null ? originalIndex - 1 : originalIndex;
231                                if (index == -1) {
232                                    assert receiver != null : "can't happen: index is -1, while function is not extension";
233                                    return new TypeAndName(receiver.getType(), originalParam.getName());
234                                }
235                                ValueParameterDescriptor parameter = superFunction.getValueParameters().get(index);
236                                return new TypeAndName(parameter.getType(), parameter.getName());
237                            }
238                        });
239    
240                VarargCheckResult varargCheckResult = checkVarargInSuperFunctions(originalParam);
241    
242                KotlinType altType = modifyTypeAccordingToSuperMethods(varargCheckResult.parameterType,
243                                                                       convertToTypeVarianceList(typesFromSuperMethods),
244                                                                       MEMBER_SIGNATURE_CONTRAVARIANT);
245    
246                if (shouldBeExtension && originalIndex == 0) {
247                    resultReceiverType = altType;
248                }
249                else {
250                    Name stableName = null;
251                    for (int i = 0; i < superFunctions.size(); i++) {
252                        if (superFunctions.get(i).hasStableParameterNames()) {
253                            // When there's more than one stable name in super functions, we pick the first one. This behaviour is similar to
254                            // the compiler front-end, except that it reports a warning in such cases
255                            // TODO: report a warning somewhere if there's more than one stable name in super functions
256                            stableName = typesFromSuperMethods.get(i).name;
257                            break;
258                        }
259                    }
260    
261                    resultParameters.add(new ValueParameterDescriptorImpl(
262                            originalParam.getContainingDeclaration(),
263                            null,
264                            shouldBeExtension ? originalIndex - 1 : originalIndex,
265                            originalParam.getAnnotations(),
266                            stableName != null ? stableName : originalParam.getName(),
267                            altType,
268                            originalParam.declaresDefaultValue(),
269                            originalParam.isCrossinline(),
270                            originalParam.isNoinline(),
271                            varargCheckResult.isVararg ? DescriptorUtilsKt.getBuiltIns(originalParam).getArrayElementType(altType) : null,
272                            SourceElement.NO_SOURCE
273                    ));
274                }
275            }
276    
277            boolean hasStableParameterNames = CollectionsKt.any(superFunctions, new Function1<FunctionDescriptor, Boolean>() {
278                @Override
279                public Boolean invoke(FunctionDescriptor descriptor) {
280                    return descriptor.hasStableParameterNames();
281                }
282            });
283    
284            return new ValueParameters(resultReceiverType, resultParameters, hasStableParameterNames);
285        }
286    
287        @NotNull
288        private static List<TypeAndVariance> convertToTypeVarianceList(@NotNull List<TypeAndName> list) {
289            return CollectionsKt.map(list, new Function1<TypeAndName, TypeAndVariance>() {
290                @Override
291                public TypeAndVariance invoke(TypeAndName tvn) {
292                    return new TypeAndVariance(tvn.type, INVARIANT);
293                }
294            });
295        }
296    
297        private static List<FunctionDescriptor> getSuperFunctionsForMethod(
298                @NotNull JavaMethod method,
299                @NotNull JavaMethodDescriptor autoMethodDescriptor,
300                @NotNull ClassDescriptor containingClass
301        ) {
302            List<FunctionDescriptor> superFunctions = Lists.newArrayList();
303    
304            // TODO: Add propagation for other kotlin descriptors (KT-3621)
305            Name name = method.getName();
306            JvmMethodSignature autoSignature = SIGNATURE_MAPPER.mapToJvmMethodSignature(autoMethodDescriptor);
307            for (KotlinType supertype : containingClass.getTypeConstructor().getSupertypes()) {
308                Collection<FunctionDescriptor> superFunctionCandidates = supertype.getMemberScope().getContributedFunctions(name, NoLookupLocation.WHEN_GET_SUPER_MEMBERS);
309                for (FunctionDescriptor candidate : superFunctionCandidates) {
310                    JvmMethodSignature candidateSignature = SIGNATURE_MAPPER.mapToJvmMethodSignature(candidate);
311                    if (KotlinToJvmSignatureMapperKt.erasedSignaturesEqualIgnoringReturnTypes(autoSignature, candidateSignature)) {
312                        superFunctions.add(candidate);
313                    }
314                }
315            }
316    
317            // sorting for diagnostic stability
318            Collections.sort(superFunctions, new Comparator<FunctionDescriptor>() {
319                @Override
320                public int compare(@NotNull FunctionDescriptor fun1, @NotNull FunctionDescriptor fun2) {
321                    FqNameUnsafe fqName1 = getFqName(fun1.getContainingDeclaration());
322                    FqNameUnsafe fqName2 = getFqName(fun2.getContainingDeclaration());
323                    return fqName1.asString().compareTo(fqName2.asString());
324                }
325            });
326            return superFunctions;
327        }
328    
329        private boolean checkIfShouldBeExtension() {
330            boolean someSupersExtension = false;
331            boolean someSupersNotExtension = false;
332    
333            for (FunctionDescriptor superFunction : superFunctions) {
334                if (superFunction.getExtensionReceiverParameter() != null)  {
335                    someSupersExtension = true;
336                }
337                else {
338                    someSupersNotExtension = true;
339                }
340            }
341    
342            if (someSupersExtension) {
343                if (someSupersNotExtension) {
344                    reportError("Incompatible super methods: some are extension functions, some are not");
345                }
346                else {
347                    return true;
348                }
349            }
350            return false;
351        }
352    
353        @NotNull
354        private VarargCheckResult checkVarargInSuperFunctions(@NotNull ValueParameterDescriptor originalParam) {
355            boolean someSupersVararg = false;
356            boolean someSupersNotVararg = false;
357            for (FunctionDescriptor superFunction : superFunctions) {
358                int originalIndex = originalParam.getIndex();
359                int index = superFunction.getExtensionReceiverParameter() != null ? originalIndex - 1 : originalIndex;
360                if (index != -1 && superFunction.getValueParameters().get(index).getVarargElementType() != null) {
361                    someSupersVararg = true;
362                }
363                else {
364                    someSupersNotVararg = true;
365                }
366            }
367    
368            KotlinType originalVarargElementType = originalParam.getVarargElementType();
369            KotlinType originalType = originalParam.getType();
370    
371            if (someSupersVararg && someSupersNotVararg) {
372                reportError("Incompatible super methods: some have vararg parameter, some have not");
373                return new VarargCheckResult(originalType, originalVarargElementType != null);
374            }
375    
376            if (someSupersVararg && originalVarargElementType == null) {
377                // convert to vararg
378    
379                assert isArrayType(originalType);
380                return new VarargCheckResult(TypeUtils.makeNotNullable(originalType), true);
381            }
382            else if (someSupersNotVararg && originalVarargElementType != null) {
383                // convert to non-vararg
384    
385                assert isArrayType(originalType);
386                return new VarargCheckResult(TypeUtils.makeNullable(originalType), false);
387            }
388            return new VarargCheckResult(originalType, originalVarargElementType != null);
389        }
390    
391        @NotNull
392        private KotlinType modifyTypeAccordingToSuperMethods(
393                @NotNull KotlinType autoType,
394                @NotNull List<TypeAndVariance> typesFromSuper,
395                @NotNull TypeUsage howThisTypeIsUsed
396        ) {
397            if (autoType.isError()) return autoType;
398    
399            if (JavaDescriptorResolverKt.getPLATFORM_TYPES()) return autoType;
400    
401            boolean resultNullable = typeMustBeNullable(autoType, typesFromSuper, howThisTypeIsUsed);
402            ClassifierDescriptor resultClassifier = modifyTypeClassifier(autoType, typesFromSuper);
403            List<TypeProjection> resultArguments = getTypeArgsOfType(autoType, resultClassifier, typesFromSuper);
404            MemberScope resultScope;
405            if (resultClassifier instanceof ClassDescriptor) {
406                resultScope = ((ClassDescriptor) resultClassifier).getMemberScope(resultArguments);
407            }
408            else {
409                resultScope = autoType.getMemberScope();
410            }
411    
412            KotlinType type = KotlinTypeImpl.create(autoType.getAnnotations(),
413                                                    resultClassifier.getTypeConstructor(),
414                                                    resultNullable,
415                                                    resultArguments,
416                                                    resultScope);
417    
418            PropagationHeuristics.checkArrayInReturnType(this, type, typesFromSuper);
419            return type;
420        }
421    
422        @NotNull
423        private List<TypeProjection> getTypeArgsOfType(
424                @NotNull KotlinType autoType,
425                @NotNull ClassifierDescriptor classifier,
426                @NotNull List<TypeAndVariance> typesFromSuper
427        ) {
428            if (typesFromSuper.isEmpty()) return autoType.getArguments();
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                        ", classifier = " + classifier + ", classifier class = " + classifier.getClass();
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                KotlinType argumentType = argument.getType();
448                List<TypeProjectionAndVariance> projectionsFromSuper = typeArgumentsFromSuper.get(parameter.getIndex());
449                List<TypeAndVariance> argTypesFromSuper = getTypes(projectionsFromSuper);
450    
451                KotlinType type = modifyTypeAccordingToSuperMethods(argumentType, argTypesFromSuper, TYPE_ARGUMENT);
452                Variance projectionKind = calculateArgumentProjectionKindFromSuper(argument, projectionsFromSuper);
453    
454                resultArguments.add(new TypeProjectionImpl(projectionKind, type));
455            }
456            return resultArguments;
457        }
458    
459        private Variance calculateArgumentProjectionKindFromSuper(
460                @NotNull TypeProjection argument,
461                @NotNull List<TypeProjectionAndVariance> projectionsFromSuper
462        ) {
463            if (projectionsFromSuper.isEmpty()) return argument.getProjectionKind();
464    
465            Set<Variance> projectionKindsInSuper = Sets.newLinkedHashSet();
466            for (TypeProjectionAndVariance projectionAndVariance : projectionsFromSuper) {
467                projectionKindsInSuper.add(projectionAndVariance.typeProjection.getProjectionKind());
468            }
469    
470            Variance defaultProjectionKind = argument.getProjectionKind();
471            if (projectionKindsInSuper.size() == 0) {
472                return defaultProjectionKind;
473            }
474            else if (projectionKindsInSuper.size() == 1) {
475                Variance projectionKindInSuper = projectionKindsInSuper.iterator().next();
476                if (defaultProjectionKind == INVARIANT || defaultProjectionKind == projectionKindInSuper) {
477                    return projectionKindInSuper;
478                }
479                else {
480                    reportError("Incompatible projection kinds in type arguments of super methods' return types: "
481                                + projectionsFromSuper + ", defined in current: " + argument);
482                    return defaultProjectionKind;
483                }
484            }
485            else {
486                reportError("Incompatible projection kinds in type arguments of super methods' return types: " + projectionsFromSuper);
487                return defaultProjectionKind;
488            }
489        }
490    
491        @NotNull
492        private static List<TypeAndVariance> getTypes(@NotNull List<TypeProjectionAndVariance> projections) {
493            List<TypeAndVariance> types = Lists.newArrayList();
494            for (TypeProjectionAndVariance projection : projections) {
495                types.add(new TypeAndVariance(projection.typeProjection.getType(),
496                                              merge(projection.varianceOfPosition, projection.typeProjection.getProjectionKind())));
497            }
498            return types;
499        }
500    
501        private static Variance merge(Variance positionOfOuter, Variance projectionKind) {
502            // Inv<Inv<out X>>, X is in invariant position
503            if (positionOfOuter == INVARIANT) return INVARIANT;
504            // Out<X>, X is in out-position
505            if (projectionKind == INVARIANT) return positionOfOuter;
506            // Out<Out<X>>, X is in out-position
507            // In<In<X>>, X is in out-position
508            // Out<In<X>>, X is in in-position
509            // In<Out<X>>, X is in in-position
510            return positionOfOuter.superpose(projectionKind);
511        }
512    
513        // Returns list with type arguments info from supertypes
514        // Example:
515        //     - Foo<A, B> is a subtype of Bar<A, List<B>>, Baz<Boolean, A>
516        //     - input: klass = Foo, typesFromSuper = [Bar<String, List<Int>>, Baz<Boolean, CharSequence>]
517        //     - output[0] = [String, CharSequence], output[1] = []
518        private static List<List<TypeProjectionAndVariance>> calculateTypeArgumentsFromSuper(
519                @NotNull ClassDescriptor klass,
520                @NotNull Collection<TypeAndVariance> typesFromSuper
521        ) {
522            // For each superclass of klass and its parameters, hold their mapping to klass' parameters
523            // #0 of Bar ->  A
524            // #1 of Bar ->  List<B>
525            // #0 of Baz ->  Boolean
526            // #1 of Baz ->  A
527            // #0 of Foo ->  A (mapped to itself)
528            // #1 of Foo ->  B (mapped to itself)
529            Multimap<TypeConstructor, TypeProjection> substitution = SubstitutionUtils.buildDeepSubstitutionMultimap(
530                    TypeUtils.makeUnsubstitutedType(klass, ErrorUtils.createErrorScope("Do not access this scope", true)));
531    
532            // for each parameter of klass, hold arguments in corresponding supertypes
533            List<List<TypeProjectionAndVariance>> parameterToArgumentsFromSuper = Lists.newArrayList();
534            for (TypeParameterDescriptor ignored : klass.getTypeConstructor().getParameters()) {
535                parameterToArgumentsFromSuper.add(new ArrayList<TypeProjectionAndVariance>());
536            }
537    
538            // Enumerate all types from super and all its parameters
539            for (TypeAndVariance typeFromSuper : typesFromSuper) {
540                for (TypeParameterDescriptor parameter : typeFromSuper.type.getConstructor().getParameters()) {
541                    TypeProjection argument = typeFromSuper.type.getArguments().get(parameter.getIndex());
542    
543                    // for given example, this block is executed four times:
544                    // 1. typeFromSuper = Bar<String, List<Int>>,      parameter = "#0 of Bar",  argument = String
545                    // 2. typeFromSuper = Bar<String, List<Int>>,      parameter = "#1 of Bar",  argument = List<Int>
546                    // 3. typeFromSuper = Baz<Boolean, CharSequence>,  parameter = "#0 of Baz",  argument = Boolean
547                    // 4. typeFromSuper = Baz<Boolean, CharSequence>,  parameter = "#1 of Baz",  argument = CharSequence
548    
549                    // if it is mapped to klass' parameter, then store it into map
550                    for (TypeProjection projection : substitution.get(parameter.getTypeConstructor())) {
551                        // 1. projection = A
552                        // 2. projection = List<B>
553                        // 3. projection = Boolean
554                        // 4. projection = A
555                        ClassifierDescriptor classifier = projection.getType().getConstructor().getDeclarationDescriptor();
556    
557                        // this condition is true for 1 and 4, false for 2 and 3
558                        if (classifier instanceof TypeParameterDescriptor && classifier.getContainingDeclaration() == klass) {
559                            int parameterIndex = ((TypeParameterDescriptor) classifier).getIndex();
560                            Variance effectiveVariance = parameter.getVariance().superpose(typeFromSuper.varianceOfPosition);
561                            parameterToArgumentsFromSuper.get(parameterIndex).add(new TypeProjectionAndVariance(argument, effectiveVariance));
562                        }
563                    }
564                }
565            }
566            return parameterToArgumentsFromSuper;
567        }
568    
569        private boolean typeMustBeNullable(
570                @NotNull KotlinType autoType,
571                @NotNull List<TypeAndVariance> typesFromSuper,
572                @NotNull TypeUsage howThisTypeIsUsed
573        ) {
574            boolean someSupersNotCovariantNullable = false;
575            boolean someSupersCovariantNullable = false;
576            boolean someSupersNotNull = false;
577            for (TypeAndVariance typeFromSuper : typesFromSuper) {
578                if (!TypeUtils.isNullableType(typeFromSuper.type)) {
579                    someSupersNotNull = true;
580                }
581                else {
582                    if (typeFromSuper.varianceOfPosition == Variance.OUT_VARIANCE) {
583                        someSupersCovariantNullable = true;
584                    }
585                    else {
586                        someSupersNotCovariantNullable = true;
587                    }
588                }
589            }
590    
591            if (someSupersNotNull && someSupersNotCovariantNullable) {
592                reportError("Incompatible types in superclasses: " + typesFromSuper);
593                return TypeUtils.isNullableType(autoType);
594            }
595            else if (someSupersNotNull) {
596                return false;
597            }
598            else if (someSupersNotCovariantNullable || someSupersCovariantNullable) {
599                boolean annotatedAsNotNull = howThisTypeIsUsed != TYPE_ARGUMENT && !TypeUtils.isNullableType(autoType);
600    
601                if (annotatedAsNotNull && someSupersNotCovariantNullable) {
602                    DescriptorRenderer renderer = DescriptorRenderer.SHORT_NAMES_IN_TYPES;
603                    reportError("In superclass type is nullable: " + typesFromSuper + ", in subclass it is not: " + renderer.renderType(autoType));
604                    return true;
605                }
606    
607                return !annotatedAsNotNull;
608            }
609            return TypeUtils.isNullableType(autoType);
610        }
611    
612        @NotNull
613        private ClassifierDescriptor modifyTypeClassifier(
614                @NotNull KotlinType autoType,
615                @NotNull List<TypeAndVariance> typesFromSuper
616        ) {
617            ClassifierDescriptor classifier = autoType.getConstructor().getDeclarationDescriptor();
618            if (!(classifier instanceof ClassDescriptor)) {
619                assert classifier != null : "no declaration descriptor for type " + autoType + ", auto method descriptor: " + autoMethodDescriptor;
620    
621                if (classifier instanceof TypeParameterDescriptor && autoTypeParameterToModified.containsKey(classifier)) {
622                    return autoTypeParameterToModified.get(classifier);
623                }
624                return classifier;
625            }
626            ClassDescriptor klass = (ClassDescriptor) classifier;
627    
628            boolean someSupersMutable = false;
629            boolean someSupersCovariantReadOnly = false;
630            boolean someSupersNotCovariantReadOnly = false;
631            for (TypeAndVariance typeFromSuper : typesFromSuper) {
632                ClassifierDescriptor classifierFromSuper = typeFromSuper.type.getConstructor().getDeclarationDescriptor();
633                if (classifierFromSuper instanceof ClassDescriptor) {
634                    ClassDescriptor classFromSuper = (ClassDescriptor) classifierFromSuper;
635    
636                    if (JavaToKotlinClassMap.INSTANCE.isMutable(classFromSuper)) {
637                        someSupersMutable = true;
638                    }
639                    else if (JavaToKotlinClassMap.INSTANCE.isReadOnly(classFromSuper)) {
640                        if (typeFromSuper.varianceOfPosition == Variance.OUT_VARIANCE) {
641                            someSupersCovariantReadOnly = true;
642                        }
643                        else {
644                            someSupersNotCovariantReadOnly = true;
645                        }
646                    }
647                }
648            }
649    
650            if (someSupersMutable && someSupersNotCovariantReadOnly) {
651                reportError("Incompatible types in superclasses: " + typesFromSuper);
652                return classifier;
653            }
654            else if (someSupersMutable) {
655                if (JavaToKotlinClassMap.INSTANCE.isReadOnly(klass)) {
656                    return JavaToKotlinClassMap.INSTANCE.convertReadOnlyToMutable(klass);
657                }
658            }
659            else if (someSupersNotCovariantReadOnly || someSupersCovariantReadOnly) {
660                if (JavaToKotlinClassMap.INSTANCE.isMutable(klass)) {
661                    return JavaToKotlinClassMap.INSTANCE.convertMutableToReadOnly(klass);
662                }
663            }
664    
665            ClassifierDescriptor fixed = PropagationHeuristics.tryToFixOverridingTWithRawType(this, typesFromSuper);
666            return fixed != null ? fixed : classifier;
667        }
668    
669        private static boolean isArrayType(@NotNull KotlinType type) {
670            return KotlinBuiltIns.isArray(type) || KotlinBuiltIns.isPrimitiveArray(type);
671        }
672    
673        private static class VarargCheckResult {
674            public final KotlinType parameterType;
675            public final boolean isVararg;
676    
677            public VarargCheckResult(KotlinType 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 KotlinType type;
699            public final Variance varianceOfPosition;
700    
701            public TypeAndVariance(KotlinType 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 KotlinType type;
713            public final Name name;
714    
715            public TypeAndName(KotlinType type, Name name) {
716                this.type = type;
717                this.name = name;
718            }
719        }
720    
721        private static class ValueParameters {
722            private final KotlinType receiverType;
723            private final List<ValueParameterDescriptor> descriptors;
724            private final boolean hasStableParameterNames;
725    
726            public ValueParameters(
727                    @Nullable KotlinType 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    }