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