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